【题解】CF1209E2 Rotate Columns (hard version)

CF1209E2】题解

一:【题意】

给定一个n*m的矩阵,每列可以循环移位任意次
记r[i]为第i行最大值,求r[1]+r[2]+...+r[n]最大值

二:【解法】

注意到,只有最大值最大的前n列会对结果造成影响,换言之,剩下的m-n列可以抛弃
此时m=n数据范围大大缩小
我们设计dp[i][S]:表示前i列中,S集合的行已经被确定了最大值,此时最大值之和的最大值为dp[i][S]
考虑转移,枚举子集T,枚举移位次数k
dp[i][S]=max(dp[i-1][T]+a[(b+k-1)%n+1][i]),b属于S^T
此时时间复杂度为O(tnn*3^n),会超时

我们考虑在枚举每一列之后,提前预处理位移的贡献
pos[S]表示循环移动任意位时,集合S对应位置的和的最大值
dp[i][S]=max(dp[i-1][T]+pos[S^T])
此时时间复杂度为O(tn3^n)

三:【代码】

#include<bits/stdc++.h>
using namespace std;
const int N=13,M=2010;
int n,m;
int mp[N][N];


//useless
vector<int> a[M];int o[M];
bool cmp(int x,int y){
	return a[x].back()>a[y].back();
}
void small(){
	for(int i=1;i<=m;i++){
		o[i]=i;
		int maxn=0;
		for(auto v:a[i]) maxn=max(maxn,v);
		a[i].push_back(maxn);
	}
	sort(o+1,o+1+m,cmp);
	m=min(m,n);
	for(int i=1;i<=m;i++){
		for(int j=0;j<n;j++) mp[j+1][i]=a[o[i]][j];
	}
}
//useless

int dp[N][1<<N],pos[1<<N];
void clear(){
	for(int i=1;i<=m;i++) a[i].clear();
}
void getpos(int tp){
	for(int st=0;st<(1<<n);st++){
		pos[st]=0;
		for(int i=0;i<n;i++){//偏移量
			int ans=0;
			for(int j=0;st>>j;j++){
				if(st>>j&1) ans+=mp[(j+i)%n+1][tp];
			}
			pos[st]=max(pos[st],ans);
		}
	}
}
void solve(){
	cin>>n>>m;
	clear();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			int k;cin>>k;
			a[j].push_back(k);
		}
	}
	small();
	for(int i=1;i<=m;i++){
		getpos(i);
		for(int S=0;S<(1<<n);S++){
			dp[i][S]=0;
			for(int T=S;;T=(T-1)&S){
				dp[i][S]=max(dp[i][S],dp[i-1][T]+pos[S^T]);
				if(T==0) break;
			}
		}
	}
	cout<<dp[m][(1<<n)-1]<<"\n";
}
int main(){
	int t;cin>>t;
	while(t--) solve();
	return 0;
}
posted @ 2025-12-18 10:02  Ming3398  阅读(2)  评论(0)    收藏  举报