题意:众所周知,白神是具有神奇的能力的。比如说,他对数学作业说一声“数”,数学作业就会出于畏惧而自己完成;对语文作业说一声“语”,语文作业就会出于畏惧而自己完成。今天,语文老师和数学老师布置了许多作业,同学们纷纷寻找白神寻求帮助。白神作为一个助人为乐的人,便答应下来。回到家,白神将这N份作业按顺序摊开,发现语文作业数学作业混在一起,这就让白神苦恼起来,他如果对连续一段作业喊出“数”,那么里面的语文作业就会由于过于慌乱而写满错解,不过如果白神再对其喊一声“语”,它又会写满正确答案。虽然白神很强大,但是能力还是有限制的,一天只能使用K次,现在,白神想知道他能正确的完成多少份作业。
如果真能这样该多好…其实最优的做法肯定是每一次覆盖都是选取前面覆盖范围内的一段,这样可以把序列分成2*K-1个不同的段,这样就可以DP辣.f[i][j][k]表示到第i个数分成j段,最后一段的值为k,转移并不困难: f[i][j][k]=max(f[i-1][j-1][k^1],f[i-1][j][k])+(a[i]==k)
Tips: 滚动数组
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=100000+10;
int f[3][101][2],n,k,a[maxn],ans;
int main()
{
//freopen("3791.in","r",stdin);
//freopen("3791.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
f[1][1][a[1]]=1;
f[1][1][a[1]^1]=0;
k=2*k-1;
for(int i=2;i<=n;i++)
{
for(int j=1;j<=k;j++)
for(int l=0;l<2;l++)
{
f[i%2][j][l]=f[(i-1)%2][j][l]+(a[i]==l);
if(j>1) f[i%2][j][l]=max(f[i%2][j][l],f[(i-1)%2][j-1][l^1]+(a[i]==l));
ans=max(ans,f[i%2][j][l]);
}
for(int j=1;j<=k;j++)
for(int l=0;l<2;l++)
f[(i+1)%2][j][l]=0;
}
printf("%d\n",ans);
return 0;
}