40pts,求hack,玄关
查看原帖
40pts,求hack,玄关
700510
AirQaQ楼主2024/10/24 21:16

本蒟蒻的思路是dp[x][i][j][k][0/1]表示在第x个木板,区间[i,j]粉刷k次且最开始把区间刷成0/1的最多的收益,因为刷总比不刷优秀,枚举i,j,k,中间点mid,那么可以从dp[x][i][mid][k-1/k][0/1],dp[x][mid+1][j][k-1/k][0/1]转移,具体代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N=51;
int dp[N][N][N][N][2],dp1[N][N*N];
int c[N][N*N];
int a[N][N],sum[N][N][2];
int n,m,T;
int q(int x,int l,int r,int op){
	return sum[x][r][op]-sum[x][l-1][op];
}
signed main(){
	cin>>n>>m>>T;
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
		char ch;
		cin>>ch;
		sum[i][j][0]=sum[i][j-1][0],sum[i][j][1]=sum[i][j-1][1];
		a[i][j]=(ch=='1'),sum[i][j][a[i][j]]++;
	}
	for(int x=1;x<=n;x++){
		for(int i=1;i<=m;i++)dp[x][i][i][1][a[x][i]]=1;
		for(int len=2;len<=m;len++){
			for(int i=1;i+len-1<=m;i++){
				int j=i+len-1;
				for(int k=1;k<=len;k++){
					dp[x][i][j][k][0]=dp[x][i][j][k-1][0];
					dp[x][i][j][k][1]=dp[x][i][j][k-1][1];
					for(int mid=i;mid<j;mid++){
						dp[x][i][j][k][0]=max(dp[x][i][mid][k][0]+q(x,mid+1,j,0),dp[x][i][j][k][0]);
						dp[x][i][j][k][0]=max(dp[x][mid+1][j][k][0]+q(x,i,mid,0),dp[x][i][j][k][0]);
						dp[x][i][j][k][0]=max(dp[x][i][mid][k-1][1]+q(x,mid+1,j,0),dp[x][i][j][k][0]);
						dp[x][i][j][k][0]=max(dp[x][mid+1][j][k-1][1]+q(x,i,mid,0),dp[x][i][j][k][0]);
						dp[x][i][j][k][1]=max(dp[x][i][mid][k][1]+q(x,mid+1,j,1),dp[x][i][j][k][1]);
						dp[x][i][j][k][1]=max(dp[x][mid+1][j][k][1]+q(x,i,mid,1),dp[x][i][j][k][1]);
						dp[x][i][j][k][1]=max(dp[x][i][mid][k-1][0]+q(x,mid+1,j,1),dp[x][i][j][k][1]);
						dp[x][i][j][k][1]=max(dp[x][mid+1][j][k-1][0]+q(x,i,mid,1),dp[x][i][j][k][1]);
					}
				}
			}
		}
		for(int i=1;i<=m;i++)c[x][i]=max({c[x][i-1],dp[x][1][m][i][0],dp[x][1][m][i][1]});
	}
	int lim=0;
	for(int i=1;i<=n;i++){
		lim+=m,lim=min(lim,T);
		for(int j=1;j<=lim;j++){
			dp1[i][j]=dp1[i-1][j];
			for(int k=0;k<=min(j,m);k++)
				dp1[i][j]=max(dp1[i-1][j-k]+c[i][k],dp1[i][j]);
		}
	}
	if(T>n*m)cout<<n*m; 
	else cout<<dp1[n][T];
	return 0;
}
2024/10/24 21:16
加载中...