震惊!!天天刷dp的人竟没有过B!!
呜呜,wa了10几发,结果是边界的脑残错误
Ⅰ . 分 析 \color{Red}Ⅰ.分析 Ⅰ.分析
这 是 个 很 明 显 的 d p , 无 后 效 性 这是个很明显的dp,无后效性 这是个很明显的dp,无后效性
原 因 是 我 们 可 以 把 在 位 置 i 往 左 走 了 q 次 的 最 大 价 值 都 记 录 下 来 原因是我们可以把在位置i往左走了q次的最大价值都记录下来 原因是我们可以把在位置i往左走了q次的最大价值都记录下来
后 续 可 以 从 任 意 一 个 位 置 转 移 后续可以从任意一个位置转移 后续可以从任意一个位置转移
Ⅱ . 两 种 D P 方 式 \color{Red}Ⅱ.两种DP方式 Ⅱ.两种DP方式
Ⅰ . 好 理 解 一 点 的 , 也 是 我 用 的 方 式 Ⅰ.好理解一点的,也是我用的方式 Ⅰ.好理解一点的,也是我用的方式
定 义 d p [ i ] [ q ] 是 当 前 在 索 引 i 位 置 且 往 左 走 了 q 次 的 最 大 价 值 定义dp[i][q]是当前在索引i位置且往左走了q次的最大价值 定义dp[i][q]是当前在索引i位置且往左走了q次的最大价值
一 般 我 们 从 i 走 到 i − 1 都 要 再 走 回 i ( 因 为 不 能 连 续 往 左 走 ) 一般我们从i走到i-1都要再走回i(因为不能连续往左走) 一般我们从i走到i−1都要再走回i(因为不能连续往左走)
所 以 特 判 一 下 终 点 是 往 左 走 但 次 数 k 用 完 不 回 来 的 情 况 所以特判一下终点是往左走但次数k用完不回来的情况 所以特判一下终点是往左走但次数k用完不回来的情况
一 般 情 况 当 ( i − 1 + q ∗ 2 ) = = k 时 就 可 以 用 d p 数 组 更 新 答 案 一般情况当(i-1+q*2)==k时就可以用dp数组更新答案 一般情况当(i−1+q∗2)==k时就可以用dp数组更新答案
所 以 在 i 点 时 , 直 接 枚 举 在 i − 1 和 i 间 来 回 走 几 次 即 可 所以在i点时,直接枚举在i-1和i间来回走几次即可 所以在i点时,直接枚举在i−1和i间来回走几次即可
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个位置间循环移动几次 不再枚举在第i个位置和i−1个位置间循环移动几次
直 接 转 移 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[i−1][j]+a[i]//i−1位置往右走
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[i−1][j+1]=max(dp[i−1][j+1],dp[i][j]+a[i−1])//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;
}
}
一起努力加油吧~