luogu 4158 粉刷匠 dp套dp
dp套dp
每个木板是个递推的dp,外部是个分组背包
#include<bits/stdc++.h> #define rep(i,x,y) for(register int i=x;i<=y;i++) using namespace std; const int N=55; const int T=2550; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f;} int n,m,t,f[N][N],dp[N][T],s[N];char s1[N]; int main(){ n=read();m=read();t=read(); for(int i=1;i<=n;i++){ memset(f,0,sizeof f); memset(s,0,sizeof s); scanf("%s",s1+1); for(int j=1;j<=m;j++) s[j]=s[j-1]+(s1[j]=='1'); //提前预处理字符串贡献,利用前缀和 for(int j=1;j<=m;j++) for(int k=1;k<=m;k++)// i,j代表前i个字母刷了j个 for(int z=0;z<j;z++){ int dis=s[j]-s[z]; f[j][k]=max(f[j][k],f[z][k-1]+max(dis,j-z-dis)); // f[j][k] 代表本行中前j格涂了k次的最大收益 } for(int j=1;j<=t;j++){ int top=min(j,m); //防止出现实际上不存在的格子 for(int k=1;k<=top;k++) dp[i][j]=max(dp[i][j],dp[i-1][j-k]+f[m][k]);} // 就算本条木板中有些不涂,向后递推,答案也不会变得更劣,所以每行的最优答案集中在f[m]上 }int ans=0;// dp i,j分别代表前i行涂了j个格子的情况 for(int i=1;i<=t;i++) ans=max(ans,dp[n][i]); printf("%d\n",ans);return 0; }