B. Array Walk(两种dp方式)

震惊!!天天刷dp的人竟没有过B!!

呜呜,wa了10几发,结果是边界的脑残错误

Ⅰ . 分 析 \color{Red}Ⅰ.分析 .

这 是 个 很 明 显 的 d p , 无 后 效 性 这是个很明显的dp,无后效性 dp,

原 因 是 我 们 可 以 把 在 位 置 i 往 左 走 了 q 次 的 最 大 价 值 都 记 录 下 来 原因是我们可以把在位置i往左走了q次的最大价值都记录下来 iq

后 续 可 以 从 任 意 一 个 位 置 转 移 后续可以从任意一个位置转移

Ⅱ . 两 种 D P 方 式 \color{Red}Ⅱ.两种DP方式 .DP

Ⅰ . 好 理 解 一 点 的 , 也 是 我 用 的 方 式 Ⅰ.好理解一点的,也是我用的方式 .,

定 义 d p [ i ] [ q ] 是 当 前 在 索 引 i 位 置 且 往 左 走 了 q 次 的 最 大 价 值 定义dp[i][q]是当前在索引i位置且往左走了q次的最大价值 dp[i][q]iq

一 般 我 们 从 i 走 到 i − 1 都 要 再 走 回 i ( 因 为 不 能 连 续 往 左 走 ) 一般我们从i走到i-1都要再走回i(因为不能连续往左走) ii1i()

所 以 特 判 一 下 终 点 是 往 左 走 但 次 数 k 用 完 不 回 来 的 情 况 所以特判一下终点是往左走但次数k用完不回来的情况 k

一 般 情 况 当 ( i − 1 + q ∗ 2 ) = = k 时 就 可 以 用 d p 数 组 更 新 答 案 一般情况当(i-1+q*2)==k时就可以用dp数组更新答案 (i1+q2)==kdp

所 以 在 i 点 时 , 直 接 枚 举 在 i − 1 和 i 间 来 回 走 几 次 即 可 所以在i点时,直接枚举在i-1和i间来回走几次即可 i,i1i

for(int i=2;i<=n;i++)
{
	dp[i][0]=dp[i-1][0]+a[i];//一直往右走
	if( i-1==k )	ans=max(ans,dp[i][0]);
	for(int q=1;q<=z;q++)//循环当前向左走了q次
	for(int j=0;j<=q;j++)//循环
	{
		int s=j*(a[i]+a[i-1]);
		dp[i][q]=max(dp[i][q],dp[i-1][q-j]+s+a[i]);
		if( i-1+q*2==k )	ans=max(ans,dp[i][q]); 
		if( i-1+q*2-1==k )	ans=max(ans,dp[i][q]-a[i]);
		//这里减去a[i],代表执行i->i-1->i这样操作(j-1)次,但最后一次只执行i->i-1,不回来了
	}
}

完整代码戳我啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊

Ⅱ . 另 一 种 方 式 Ⅱ.另一种方式 .

状 态 还 是 相 同 , 转 移 大 同 小 异 状态还是相同,转移大同小异 ,

不 再 枚 举 在 第 i 个 位 置 和 i − 1 个 位 置 间 循 环 移 动 几 次 不再枚举在第i个位置和i-1个位置间循环移动几次 ii1

直 接 转 移 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + a [ i ] / / i − 1 位 置 往 右 走 直接转移dp[i][j]=dp[i-1][j]+a[i]//i-1位置往右走 dp[i][j]=dp[i1][j]+a[i]//i1

d p [ i − 1 ] [ j + 1 ] = m a x ( d p [ i − 1 ] [ j + 1 ] , d p [ i ] [ j ] + a [ i − 1 ] ) / / i 位 置 往 左 走 dp[i-1][j+1]=max(dp[i-1][j+1],dp[i][j]+a[i-1])//i位置往左走 dp[i1][j+1]=max(dp[i1][j+1],dp[i][j]+a[i1])//i

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int long long
int t,k,z,a[100009],dp[100009][6],n;
signed main()
{
	cin >> t;
	while( t-- )
	{
		int ans=0;
		cin >> n >> k >> z;
		for(int i=1;i<=n;i++)	scanf("%lld",&a[i]);
		dp[1][0]=a[1];
		for(int i=2;i<=n;i++)
		for(int j=0;j<=z;j++)
		{
			dp[i][j]=dp[i-1][j]+a[i];//直接从i-1走过来
			if( i-1+j*2==k )	ans=max(ans,dp[i][j]); 
			if( j+1<=z )
				dp[i-1][j+1]=max(dp[i-1][j+1],dp[i][j]+a[i-1]);//也可以从i走回i-1 
			if( (i-1)-1+(j+1)*2==k )	ans=max(ans,dp[i-1][j+1]);
		}
		for(int i=0;i<=n;i++)
		for(int j=0;j<=z;j++)
			dp[i][j]=0;
		cout << ans << endl;
	}
}

一起努力加油吧~

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值