题目大意
有两个序列,可以调换两个序列相应的位置的元素,求最少步骤使得每个序列所含元素互不相同。
解题思路
可以发现一个元素最多出现两次,必须在不同序列,所以我们可以枚举一个元素的状态,便可以确定一个连通块的状态。注意有多个连通块,它们相互独立。
code
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const maxn=50000,maxx=100000,inf=2147483647;
int n,gra,to[maxn*2+10],next[maxn*2+10],begin[maxn+10],a[maxn+10],b[maxn+10],c[maxx+10][10],
queue[maxn+10],tag[maxn+10];
bool visit[maxn+10],done[maxn+10];
void insert(int u,int v){
if(u==v)return;
to[++gra]=v;
next[gra]=begin[u];
begin[u]=gra;
}
int coun(int t,int u,int v){
int re;
if(t)swap(a[u],b[u]);
if((a[u]==a[v])||(b[u]==b[v]))re=1;else re=0;
if(t)swap(a[u],b[u]);
return re;
}
int bfs(int u,int v){
int head=0,tail=0,sum=v;
visit[queue[++tail]=u]=1;
tag[u]=v;
for(;head!=tail;){
int now=queue[++head];
for(int i=begin[now];i;i=next[i])
if(!visit[to[i]]){
sum+=(tag[to[i]]=coun(tag[now],now,to[i]));
visit[queue[++tail]=to[i]]=1;
}else if(tag[to[i]]!=coun(tag[now],now,to[i]))return inf;
}
fo(i,1,tail)done[queue[i]]=1,visit[queue[i]]=0;
return sum;
}
int main(){
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%d",&n);
fo(i,1,n)scanf("%d",&a[i]),c[a[i]][++c[a[i]][0]]=i;
fo(i,1,n)scanf("%d",&b[i]),c[b[i]][++c[b[i]][0]]=i;
fo(i,1,maxx)if(c[i][0]>1)insert(c[i][1],c[i][2]),insert(c[i][2],c[i][1]);
int ans=0;
fo(i,1,n)
if(!done[i])
ans+=min(bfs(i,0),bfs(i,1));
printf("%d",ans);
return 0;
}