P4158 [SCOI2009]粉刷匠(dp)

考虑每行独立计算。

所以可以开一个三维数组: g [ i ] [ j ] [ k ] g[i][j][k] g[i][j][k] i i i行前 j j j列涂了 k k k次的最大值。

然后再开一个 二维数组 f [ i ] [ j ] f[i][j] f[i][j]表示前 i i i行涂了 j j j次的最大值。

预处理二维前缀和。

然后 g g g 的递推 O ( n m 3 ) O(nm^3) O(nm3) f f f的递推 O ( n m T ) O(nmT) O(nmT)

// Problem: P4158 [SCOI2009]粉刷匠
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4158
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2021-08-24 15:37:22
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=55,M=2505,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define IOS ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\n",a[n]); 
}
int n,m,T;
char a[N];
int s[N][N],f[N][M];
int g[N][N][N];//第i行前j列涂k次的最大值.
int main(){
	scanf("%d%d%d",&n,&m,&T);
	for(int i=1;i<=n;i++){
		scanf("%s",a+1);
		for(int j=1;j<=m;j++)
			s[i][j]=s[i][j-1]+(a[j]=='1');
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			for(int k=1;k<=m;k++)
				for(int x=k-1;x<j;x++){
	g[i][j][k]=max(g[i][j][k],g[i][x][k-1]+max(s[i][j]-s[i][x],j-x-s[i][j]+s[i][x]));
				}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=T;j++)
			for(int k=0;k<=min(j,m);k++)
				f[i][j]=max(f[i][j],f[i-1][j-k]+g[i][m][k]);
	int ans=0;
	for(int i=1;i<=T;i++)
		ans=max(ans,f[n][i]);
	printf("%d\n",ans);
	return 0;
}