版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/91410588
题目:POJ2888.
题目大意:给定一个长度为
的环状数列,在这个环状数列上取
个数,其中每一个极大连续段的开头没有贡献,其余均有贡献,求最大贡献和.
.
首先不考虑这是个环而是个序列,直接DP.设
表示第
到
个数中取了
个数且第
个数不选
选的最大贡献和,容易列出方程:
初态 ,答案 .显然这个DP可以做到 .
考虑如何把这个做法拓展到环上.
重新考虑一下我们漏掉了哪种情况,发现只漏掉了一种第 个和第 个同时选的情况,这个情况下貌似只需要把初态改成 ,答案变为 即可.
于是我们只需要跑两遍DP即可解决这个问题,时空复杂度 .
然而这个做法在POJ上会爆空间,所以需要滚动数组优化一下空间复杂度.
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=3830,INF=(1<<30)-1;
int n,m,a[N+9],ans,dp[N+9][2];
void Pre_dp(){
for (int j=0;j<=m;++j)
for (int k=0;k<2;++k)
dp[j][k]=-INF;
}
void Solve_dp(){
for (int i=2;i<=n;++i)
for (int j=m;j>=0;--j){
dp[j][0]=max(dp[j][0],dp[j][1]);
if (j>0) dp[j][1]=max(dp[j-1][0],dp[j-1][1]+a[i]);
}
}
Abigail into(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i)
scanf("%d",&a[i]);
}
Abigail work(){
if (n<2) return;
Pre_dp();
dp[0][0]=dp[1][1]=0;
Solve_dp();
ans=max(dp[m][0],dp[m][1]);
Pre_dp();
dp[1][1]=a[1];
Solve_dp();
ans=max(ans,dp[m][1]);
}
Abigail outo(){
printf("%d\n",ans);
}
int main(){
into();
work();
outo();
return 0;
}