Loading

题解 lg4158 [SCOI2009]粉刷匠

题意

给 N 条每条被划分成 M 个格子的木板每个格子刷颜色,每一次刷只能刷一条木板连续的一段,且每一个格子最多只能粉刷一次,一共只能刷 T 次,问能够正确的刷多少格子.

思路

有一个很显然的性质,就是一条木板要是要涂就一定会涂满但bakaのfpjo显然没有注意到这一点

且还有 每一个格子最多只能粉刷一次

然后就很好来写dp转移了

\(g(i,j,k)\)\(i\) 条木板的前\(j\)个格子涂上\(k\)次的最大正确粉刷格子数,\(pre(i,j)\)表示第\(i\)条木板的前\(j\)个格子中蓝色的数量明显有

\[g(i,j,k)=max_{0\leq l \leq j}(g(i,l,k-1)+max(pre(j)-pre(l),i-l-(pre(j)-pre(l)))) \]

然后考虑\(f(i,k)\)表示前\(i\)条木板涂\(k\)次的最大答案

\[f(i,k)=max_{0\leq j \leq k}(f(i-1,k-j)+g(i,m,j)) \]

代码

#include<bits/stdc++.h>
using namespace std;
int const MAXN=60,MAXT=2600;
int n,m,T,ans=0;
int pre[MAXN][MAXN],g[MAXN][MAXN][MAXT],f[MAXN][MAXT];
char str[MAXN];
int main(){
	scanf("%d%d%d",&n,&m,&T);
	for(int i=1;i<=n;i++){
		scanf("%s",str+1);
		for(int j=1;j<=m;j++){
			pre[i][j]=(str[j]=='1')+pre[i][j-1];
		}
	}
	for(int i=1;i<=n;i++){
		for(int k=1;k<=min(T,m);k++){
			for(int j=1;j<=m;j++){
				for(int l=0;l<=j;l++){
					g[i][j][k]=max(g[i][j][k] , g[i][l][k-1]+max( pre[i][j]-pre[i][l],(j-l)-(pre[i][j]-pre[i][l]) ) );
				}
			}
		}
	}
	for(int k=1;k<=T;k++){
		for(int j=0;j<=min(k,m);j++){
			for(int i=1;i<=n;i++){
				f[i][k]=max(f[i][k],f[i-1][k-j]+g[i][m][j]);
				ans=max(ans,f[i][k]);
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2020-11-20 08:49  fpjo  阅读(61)  评论(0编辑  收藏  举报