题解:CF358D Dima and Hares

CF358D 题解

题面

原题传送门

思路

挺好的一道 DP 题。

首先分析题目会发现这道题的 DP 有点特殊:每一个点的状态会与前后两道题的状态相互影响与改变。

而观察到,一个点 i 的状态均可以表示成如下两种情况。

  1. 先选第 i+1 个物品,再取第 i 个物品。(取物品的操作并不一定是相邻的,只是第 i 个物品在取了第 i+1 个物品后取的。)
  2. 先选第 i 个物品,再选第 i+1 个物品。(取物品的操作并不一定是相邻的,只是第 i+1 个物品在取了第 i 个物品后取的。)

于是很容易想到可以设一个二维的 dp 数组:dp[i][2]

  1. dp[i][0] 表示先取第 i+1 个物品获得的前 i 个物品的最大值。
  2. dp[i][1] 表示后取第 i+1 个物品获得的前 i 个物品的最大值。

接下来就开始推递推方程。

对于一个 dp[i][0],是先取第 i+1 个物品,后取第 i 个物品,这个时候只要讨论 dp[i1] 的两种状态即可。

  1. 对于 dp[i1][0] 是先取第 i 个物品,后取第 i1 个物品,此时取第 i 个物品的时候,相邻的两个物品有一个被拿过,所以得到的价值为 b[i]
  2. 对于 dp[i1][1] 是先取第 i1 个物品,后取第 i 哥物品,此时取第 i 个物品的时候,相邻的两个物品都被拿过,所以得到的价值为 c[i]

因此 dp[i][0]=max(dp[i1][0]+b[i],dp[i1][1]+c[i])

对于一个 dp[i][1],是先取第 i 个物品,后取第 i+1 个物品,这个时候一样的讨论 dp[i1] 的两种状态即可。

  1. 对于 dp[i1][0] 是先取第 i 个物品,后取第 i1 个物品,此时取第 i 个物品的时候,相邻的两个物品都没有被拿过,所以得到的价值为 a[i]
  2. 对于 dp[i1][1] 是先取第 i1 个物品,后取第 i 哥物品,此时取第 i 个物品的时候,相邻的两个物品有一个被拿过,所以得到的价值为 b[i]

因此 dp[i][1]=max(dp[i1][0]+a[i],dp[i1][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;
} 
posted @   naroto2022  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
花开如火,也如寂寞。