[SCOI2009]粉刷匠 [动态规划]

[BZOJ1296] [luoguP4158]

第一眼没看出来emmm...

所以就先想只有一条木板怎么做 即\(f[i][j]\)表示前\(i\)个格子刷\(j\)次最多能刷正确多少个格子

然后很容易就能想到n条木板就可以将其进行01背包来算最多能刷正确有多少个格子

因为每个格子最多刷一次 所以枚举\(j\)\(j\)得小于等于\(i\)

#include<bits/stdc++.h>
using namespace std;
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)<(y)?(x):(y))
const int N=50+5,M=2500+5,inf=0x3f3f3f3f,P=19650827;
int n,m,t,ans=0,sum[N],f[N][M],nw[N][N];
char S[N];
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

int main(){
	freopen("in2.txt","r",stdin);
	//freopen("xor.out","w",stdout);
	rd(n),rd(m),rd(t);
	memset(f,0,sizeof(f));
	for(int x=1;x<=n;++x){
		scanf("%s",S+1);
		for(int i=1;i<=m;++i) sum[i]=sum[i-1]+(S[i]=='1');
		for(int i=1;i<=m;++i)//前i个格子 
		for(int j=1;j<=i;++j){//涂j次
			nw[i][j]=0;
			for(int k=0;k<i;++k)//由前k个格子转移过来 
				nw[i][j]=Max(nw[i][j],nw[k][j-1]+Max(sum[i]-sum[k],i-k-(sum[i]-sum[k])));
		}
		for(int i=1;i<=t;++i)
		for(int j=1;j<=Min(i,m);++j)
		f[x][i]=Max(f[x][i],f[x-1][i-j]+nw[m][j]);
	}
	for(int i=1;i<=t;++i) ans=Max(ans,f[n][i]);
	printf("%d",ans);
	return 0;
}
posted @ 2019-08-21 21:51  委屈的咸鱼鱼鱼鱼  阅读(206)  评论(0编辑  收藏  举报