CF1773A Amazing Trick 题解
前言
感谢 HMZ 大佬在我 一直调不出 Test #5 时给了一些点拨,在经过 也算警示后人吧
解法
本题可以使用随机化做法。
记
又因为排列
这样,原问题就转化为了构造一个排列
实现
先用一个 std::vector 顺序存储 vector 中随机选取一个数
如果找了非常多遍都没有合法的
找到
放代码:
#include<bits/stdc++.h>
using namespace std;
mt19937 rng(time(0));
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int t; cin>>t;
while(t--){
int n; cin>>n;
vector<int> a(n),m(n),q(n),p(n);
for(auto &i:a)cin>>i,i--;
for(int i=0;i<n;i++)
m[a[i]]=i;
bool w=false;
for(int _=0;_<80;_++){ // 找 80 遍(这个数足够大)
bool f=true;
vector<int> v;
iota(q.begin(),q.end(),0),v=q;
for(int i=0;i<n;i++){
for(int _=0;_<10;_++){
int k=rng()%v.size();
if(v[k]==i||v[k]==m[i])continue;
else{q[i]=v[k],v.erase(v.begin()+k); break;}
// 判断 k 的合法性
}
if(q[i]==i||q[i]==m[i]){f=false; break;}
}
if(f){w=true; break;} // 找到了
}
if(w){
cout<<"Possible\n";
for(int i=0;i<n;i++)
p[q[i]]=m[i]; // 根据排列 q 构造排列 p
for(int i:p)cout<<i+1<<' ';
cout<<'\n';
for(int i:q)cout<<i+1<<' ';
cout<<'\n';
}
else cout<<"Impossible\n"; // 无解
}
return 0;
}