Connecting...

P9120 [春季测试 2023] 密码锁 解题报告

P9120 [春季测试 2023] 密码锁 解题报告

先导:

本人很,贺了题解随机化做法,鬼知道为什么能过,但不失为一种启发。

解法

首先,题解都提到的:依次对每一个圈转,转到当前最不错的位置。

显然这是有后效性的,即每一次精心挑选会影响后世。

然后我们就让这个依次的顺序改变了,理由是:一个最优的答案就是通过一系列的操作序列得到的,我们在做的相当于枚举了一堆不错的操作序列,不断接近答案。

Code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+10,inf=INT_MAX;
int n,k,t;
/*k==1*/int mx1,mn1;
/*k!=1*/
int a[maxn+10][6]/*a[n][k] n列n串*/;
int mx[maxn+10],mn[maxn+10];
int main(){
//	freopen("lock5.in","r",stdin);
//	freopen("my.out","w",stdout);
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>t>>k;
	if(k==1){
		while(t--){
			cin>>n;
			int mx1=0,mn1=INT_MAX,a1;
			while(n--)cin>>a1,mn1=min(mn1,a1),mx1=max(mx1,a1);
			cout<<mx1-mn1<<"\n";
		}
		return 0;
	}int cnt=(k==4?124:40);
	while(t--){
		cin>>n;int ans=inf;
		for(int i=0;i<k;++i)for(int j=1;j<=n;++j)cin>>a[j][i];
		for(int H=1;H<cnt;++H){
			random_shuffle(a+1,a+1+n);//打乱n串顺序 
			memset(mx,-0x3f,sizeof mx);
			memset(mn, 0x3f,sizeof mn);//每行极值 
			for(int i=n;i>=1;--i){//正在贪i列 
				int lst=inf,pos=0;
				for(int op=1;op<=k;++op){//转op次
					int res=0;
					for(int j=0;j<k;++j){  
						int tmp=(op+j)%k;
						res=max(res,max(mx[tmp],a[i][j])-min(mn[tmp],a[i][j]));
					}
					if(lst>res)lst=res,pos=op;
				}
				for(int j=0;j<k;++j){
					int tmp=(pos+j)%k;
					mx[tmp]=max(mx[tmp],a[i][j]);
					mn[tmp]=min(mn[tmp],a[i][j]);
				}
			}
			int res=0;
			for(int i=0;i<k;++i)res=max(res,mx[i]-mn[i]);
			ans=min(ans,res);
		}
		cout<<ans<<"\n";
	}
	 
	return 0;
} 

测评记录

总感觉很是玄学。

posted @ 2024-10-05 16:52  余亦宸  阅读(57)  评论(0)    收藏  举报