题解:CF358D Dima and Hares
CF358D 题解
题面
思路
挺好的一道 DP 题。
首先分析题目会发现这道题的 DP 有点特殊:每一个点的状态会与前后两道题的状态相互影响与改变。
而观察到,一个点 i 的状态均可以表示成如下两种情况。
- 先选第 i+1 个物品,再取第 i 个物品。(取物品的操作并不一定是相邻的,只是第 i 个物品在取了第 i+1 个物品后取的。)
- 先选第 i 个物品,再选第 i+1 个物品。(取物品的操作并不一定是相邻的,只是第 i+1 个物品在取了第 i 个物品后取的。)
于是很容易想到可以设一个二维的 dp 数组:dp[i][2]。
- dp[i][0] 表示先取第 i+1 个物品获得的前 i 个物品的最大值。
- dp[i][1] 表示后取第 i+1 个物品获得的前 i 个物品的最大值。
接下来就开始推递推方程。
对于一个 dp[i][0],是先取第 i+1 个物品,后取第 i 个物品,这个时候只要讨论 dp[i−1] 的两种状态即可。
- 对于 dp[i−1][0] 是先取第 i 个物品,后取第 i−1 个物品,此时取第 i 个物品的时候,相邻的两个物品有一个被拿过,所以得到的价值为 b[i]。
- 对于 dp[i−1][1] 是先取第 i−1 个物品,后取第 i 哥物品,此时取第 i 个物品的时候,相邻的两个物品都被拿过,所以得到的价值为 c[i]。
因此 dp[i][0]=max(dp[i−1][0]+b[i],dp[i−1][1]+c[i])。
对于一个 dp[i][1],是先取第 i 个物品,后取第 i+1 个物品,这个时候一样的讨论 dp[i−1] 的两种状态即可。
- 对于 dp[i−1][0] 是先取第 i 个物品,后取第 i−1 个物品,此时取第 i 个物品的时候,相邻的两个物品都没有被拿过,所以得到的价值为 a[i]。
- 对于 dp[i−1][1] 是先取第 i−1 个物品,后取第 i 哥物品,此时取第 i 个物品的时候,相邻的两个物品有一个被拿过,所以得到的价值为 b[i]。
因此 dp[i][1]=max(dp[i−1][0]+a[i],dp[i−1][1]+b[i])。
故我们就可以线性求出 dp 数组了。
接下来,题目询问获得的最大价值,注意到第 n 个物品只可能是先取第 n 个物品,后取第 n+1 个物品,因为不存在第 n+1 个物品。
故答案为 dp[n][1]。
注意,一开始要初始化,给 dp 赋值成一个极小值(我因为没做这个,WA 过。)。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define INF 0x7fffffff/2
using namespace std;
const int MN=3005;
long long n,a[MN],b[MN],c[MN],dp[MN][2];
//dp[i][0] 表示先取第 i+1 个物品获得的前 i 个物品的最大值。
//dp[i][1] 表示后取第 i+1 个物品获得的前 i 个物品的最大值。
int main(){
scanf("%lld",&n);
for(int i=1; i<=n; i++) scanf("%lld",&a[i]);
for(int i=1; i<=n; i++) scanf("%lld",&b[i]);
for(int i=1; i<=n; i++) scanf("%lld",&c[i]);
for(int i=0; i<=n; i++) for(int j=0; j<=n; j++) dp[i][j]=-INF;
dp[0][0]=0;
for(int i=1; i<=n; i++){
dp[i][0]=max(dp[i-1][0]+b[i],dp[i-1][1]+c[i]);
dp[i][1]=max(dp[i-1][0]+a[i],dp[i-1][1]+b[i]);
}
printf("%lld",dp[n][1]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现