【AGC038F】Two Permutations
【AGC038F】Two Permutations
by AmanoKumiko
Description
给定两个\(0\ -\ N-1\)的排列\(p,q\)
构造排列\(a,b\),且\(a_i=i\)或\(p_i\),\(b\)同理
求出\(max(\sum[a_i\not=b_i])\)
Input
第一行一个整数\(N\),表示排列长度
第二行\(N\)个整数,\(p_0 ... p_{N-1}\)
第三行\(N\)个整数,\(q_0 ... q_{N-1}\)
Output
一行一个整数表示答案
Sample Input
5
1 3 2 0 4
3 0 2 1 4
Sample Output
3
Data Constraint
\(1\le N\le 10^5\)
Solution
你考虑这样一件事,就是说:把排列看成置换
那么一个排列,要么全部保留,要么全部换成对应的\(i\)
你考虑这样一件事,就是说:建出一个网络流模型
我们规定,\(P\)划分到\(S\)为保留,\(Q\)划分到\(T\)为保留
同时,我们考虑最小化\(a_i=b_i\)的个数
\(1.P\not =Q\),不用连边,直接加上贡献
\(2.P\not =i,Q=i\),那么\(a_i=b_i\)当且仅当\(P\)不保留,\(Q\)保留,即\(S\)向\(P\)连边,边权为\(1\)
\(3.P=i,Q\not =i\),那么\(a_i=b_i\)当且仅当\(P\)保留,\(Q\)不保留,即\(Q\)向\(T\)连边,边权为\(1\)
\(4.P\not =i,Q\not=i,P\not =Q\),那么\(a_i=b_i\)当且仅当\(P,Q\)均不保留,即\(Q\)向\(P\)连边,边权为\(1\)
\(5.P\not=i,Q\not=i,P=Q\),那么\(a_i=b_i\)当且仅当\(P,Q\)均保留或均不保留,即\(P\)向\(Q\)连,\(Q\)向\(P\)连,边权都为\(1\)
Code
#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define N 200010
#define inf 2147483647
int na[N],nb[N],ta,tb,n,a[N],b[N],vis[N],ans,S,T;
int gap[N],dis[N],cur[N],last[N],tot=1;
struct node{int en,v,next;}e[N*10];
void add(int x,int y,int z){e[++tot]=(node){y,z,last[x]};last[x]=tot;}
int dfs(int x,int flow){
if(x==T)return flow;
int have=0;
for(int i=cur[x];i;i=e[i].next){
cur[x]=i;
int y=e[i].en;
if(dis[x]!=dis[y]+1||!e[i].v)continue;
int now=dfs(y,min(flow-have,e[i].v));
e[i].v-=now;
e[i^1].v+=now;
have+=now;
if(have==flow)return have;
}
cur[x]=last[x];
if(!(--gap[dis[x]]))dis[0]=T+1;
++gap[++dis[x]];
return have;
}
int main(){
scanf("%d",&n);
F(i,1,n)scanf("%d",&a[i]),a[i]++;
F(i,1,n)scanf("%d",&b[i]),b[i]++;
F(i,1,n){
ta++;
for(int now=a[i];!vis[now];now=a[now]){
na[now]=ta;vis[now]=1;
}
}
memset(vis,0,sizeof(vis));
F(i,1,n){
tb++;
for(int now=b[i];!vis[now];now=b[now]){
nb[now]=tb;vis[now]=1;
}
}
S=0;T=ta+tb+1;
F(i,1,n){
if(a[i]==i&&b[i]==i)ans++;
if(a[i]==i&&b[i]!=i)add(nb[i]+ta,T,1),add(T,nb[i]+ta,0);
if(a[i]!=i&&b[i]==i)add(S,na[i],1),add(na[i],S,0);
if(a[i]!=i&&b[i]!=i){
if(a[i]==b[i])add(nb[i]+ta,na[i],1),add(na[i],nb[i]+ta,0),add(na[i],nb[i]+ta,1),add(nb[i]+ta,na[i],0);
else add(nb[i]+ta,na[i],1),add(na[i],nb[i]+ta,0);
}
}
gap[0]=T+1;
while(dis[S]<T+1)ans+=dfs(S,inf);
printf("%d",n-ans);
return 0;
}