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;
}
总感觉很是玄学。

浙公网安备 33010602011771号