题解 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;
}