题解:CF1385G Columns Swaps
xiaozekai11 · · 题解
题意转化
给你一个
显然,对于某个数
思路
从一个连通分量的任一节点处开始 bfs 遍历,如果
要求最小操作次数,可以将求出的
易错点
- 多测,所有数组最好都清空。
- 算完
ans 如果边整体取反,记得真的去改变边的标记。
参考代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
using pii=pair<ll,ll>;
ll T,n,a[210000],b[210000],cnt[210000],vis[210000],f[210000];
vector<pii> h[210000],o[210000];
vector<int> ans,c;
queue<int> q;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n;
ans.clear();
while(!q.empty()) q.pop();
for(int i=1;i<=n;i++)o[i].clear(),h[i].clear(),cnt[i]=vis[i]=0;//多测清空
for(int i=1;i<=n;i++)cin>>a[i],cnt[a[i]]++;
for(int i=1;i<=n;i++)cin>>b[i],cnt[b[i]]++;
bool ok=1;
for(int i=1;i<=n;i++)if(cnt[i]!=2)ok=0;
if(!ok){
cout<<-1<<'\n';
continue;
}
for(int i=1;i<=n;i++){
o[a[i]].push_back({i,0});
o[b[i]].push_back({i,1});
}
for(int i=1;i<=n;i++){
pii p=o[i][0],q=o[i][1];
ll w=1^p.second^q.second;
h[p.first].push_back({q.first,w});
h[q.first].push_back({p.first,w});//转换为一条双向边
}
for(int s=1;s<=n&&ok;s++){
if(vis[s])continue;
c.clear();
vis[s]=1;f[s]=0;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
c.push_back(u);
for(auto [v,w]:h[u]){
int x=f[u]^w;
if(!vis[v]){
vis[v]=1;f[v]=x;
q.push(v);
}else if(f[v]!=x){
ok=false;//判无解
}
}
}
if(!ok)break;
ll ca=0;
for(int e:c)ca+=f[e];
ll cb=(ll)c.size()-ca;
if(cb<ca)for(int e:c)f[e]^=1;//可以整体取反来最小化答案
for(int e:c)if(f[e])ans.push_back(e);
}
if(!ok){cout<<-1<<'\n';continue;}
cout<<ans.size()<<'\n';
for(int x:ans)cout<<x<<' ';
cout<<'\n';
}
return 0;
}