前言
思路
状态表示
f
[
i
]
[
j
]
:
f[i][j] :
f[i][j]: 前
i
i
i个点,并且选择了
k
k
k个区间的最大价值
状态计算 :
- 不选择当前
i
i
i端点为右端点
f [ i ] [ j ] = f [ i − 1 ] [ j ] f[i][j] = f[i-1][j] f[i][j]=f[i−1][j] - 选择当前的
i
i
i端点
f [ i ] [ j ] = m a ( f [ i − 1 ] [ j ] , f [ i − m ] [ j − 1 ] + s u m [ i ] − s u m [ i − m ] ) f[i][j] = ma(f[i-1][j],f[i-m][j-1] +sum[i] - sum[i-m]) f[i][j]=ma(f[i−1][j],f[i−m][j−1]+sum[i]−sum[i−m])
(从一个区间转移过来)
MyCode
int n,m,k;
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
sum[i] = sum[i-1] + a[i];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++){
//不选第i个点
dp[i][j] = dp[i-1][j];
if(i - m +1 >= 1)
dp[i][j] = max(dp[i-1][j],dp[i-m][j-1] + sum[i] - sum[i- m ]);
}
cout<<dp[n][k]<<endl;
另言
比赛中 状态转移方程错了,又因为比赛的缘故,其实 W A WA WA的时候脑袋已经一团浆
糊了(心里承受压力能力不够)。
现在补完之后,才发现 虽然我的状态 f [ i ] [ j ] f[i][j] f[i][j]表示当前 k k k次选取, j j j为右端点的情况
和我补的正好相反。但是其实都是有解的,只是状态转移错了
首先动态规划 要满足 :
- 最小子结构
- 无后效性
显然我倒序枚举 k k k的时候,使用了 i − 1 i-1 i−1 层的状态,也就是使用了 还没处理到的状态 显然是错的。因为我们 动态规划 是使用已经处理出来的状态去更新还未处理的状态。因此这个是 不满足后效性的
for(int i = k ; i >= 1 ; i -- ){
for(int j= 1; j<=n ; j++){
for(int t = j - m; t >= 0 ; t -- )
if(j + m <= n )
dp[i-1][j] = max(dp[i-1][j] ,dp[i][t] + sum[j+m] - sum[j]);
}
}
但是稍作修改,我们从正向枚举
k
k
k,每次都使用前面一层已经处理好的状态
那么就是答案了
for(int i=1;i<=k;i++){
for(int j=1;j<=n;j++){
dp[i][j] = dp[i][j-1];
if(j- m +1 >=1)
dp[i][j] = max(dp[i][j-1],dp[i-1][j-m]+sum[j] - sum[j-m]);
}
}
看吧,其实只要稍作修改就可以 A C AC AC,但是那时候状态和脑回路完全断线,所以继续提升咯Orz