題目鏈接:bzoj1296
題目大意:
windy有 N 條木板需要被粉刷。 每條木板被分爲 M 個格子。 每個格子要被刷成紅色或藍色。 windy每次粉刷,只能選擇一條木板上一段連續的格子,然後塗上一種顏色。 每個格子最多隻能被粉刷一次。 如果windy只能粉刷 T 次,他最多能正確粉刷多少格子? 一個格子如果未被粉刷或者被粉刷錯顏色,就算錯誤粉刷。
題解:
亂搞(?)+揹包
很明顯,每條木板的粉刷是獨立的,於是我們可以先處理出第
然後放在一起做一下揹包就可以了。
但是怎麼處理啊><
zz的我一開始根本沒有想着可以有一些格子來錯誤粉刷以獲得更多的分數。
因爲每個格子最多隻能刷一次,所以對於一段連續被刷了某種顏色的格子們來說,他們的最大貢獻就是max{白格子數,黑格子數}。
我們設
枚舉上一次刷到的最右端
那麼有
那些格子是指
揹包應該不用說
設
常規搞辣
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int sum[60],f[60][3100],g[60][60];char s[60];
//g[i][j]表示前i個格子刷j次
//f[i][j]表示前i行刷j次
int mymax(int x,int y){return (x>y)?x:y;}
int mymin(int x,int y){return (x<y)?x:y;}
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int i,j,k,l,n,m,T,ans=0;
scanf("%d%d%d\n",&n,&m,&T);
memset(f,0,sizeof(f));
for (i=1;i<=n;i++)
{
scanf("%s",s+1);
sum[0]=0;
for (j=1;j<=m;j++) sum[j]=sum[j-1]+(s[j]=='0');
memset(g,0,sizeof(g));
for (j=1;j<=m;j++)
for (k=1;k<=m;k++)
{
g[j][k]=g[j-1][k];
for (l=0;l<j;l++)
g[j][k]=mymax(g[j][k],g[l][k-1]+mymax(sum[j]-sum[l],(j-l)-(sum[j]-sum[l])));
}
for (j=T;j>=0;j--)
for (k=mymin(j,m);k>=0;k--)
f[i][j]=mymax(f[i][j],f[i-1][j-k]+g[m][k]);
}
for (i=0;i<=T;i++) ans=mymax(ans,f[n][i]);
printf("%d\n",ans);
return 0;
}