ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AGC038F Two Permutations

2022-07-28 09:04:42  阅读:162  来源: 互联网

标签:int lim 置换 Permutations Two dep res AGC038F neq


Description

给定两个 \(0 \sim (n - 1)\) 的排列 \(\{p_0, p_1, \ldots , p_{n - 1}\}\) 和 \(\{q_0, q_1, \ldots , q_{n - 1}\}\),要求构造两个 \(0 \sim (n - 1)\) 的排列 \(\{A_0, A_1, \ldots , A_{n - 1}\}\) 和 \(\{B_0, B_1, \ldots , B_{n - 1}\}\),且必须满足: \(A_i\) 要么等于 \(i\),要么等于 \(p_i\),\(B_i\) 要么等于 \(i\),要么等于 \(q_i\)。

最大化 \(A_i \ne B_i\) 的下标 \(i\) 的数量。

\(n\le 10^5\)

Solution

将答案置为 \(n\) 再减少。\(p_i=q_i=i\) 的 \(i\) 必然让答案减少 \(1\) 。

根据每个位置在两个排列上是否选择走置换环分情况讨论:

  • \(p_i=i\) 或者 \(q_i=i\),另一个选择不走置换环会导致答案减少

  • \(p_i=q_i\) 都走或者都不走置换环会导致答案减少

  • \(p_i\neq q_i\) ,都不走会导致答案减少

用最小割来刻画答案的减量。如果 \(p,q\) 中两个置换分到了和 \(S/T\) 连通的同一个集合则视为置换环转的情况相异,将 \(p\) 中转的置换分入 \(S\) 集合,\(q\) 中转的置换分入 \(T\) 集合,连边如下:

  • \(p_i=i,q_i\neq i\) 则 \(q_i\) 所在置换不旋转(分到 \(S\) 集合中)时答案减少,于是对应该置换的点和 \(T\) 连流量为 \(1\) 的边

  • \(p_i\neq i,q_i=i\) 同上,只不过变成了 \(p\) 中的点和 \(S\) 连

  • \(p_i,q_i\neq i,p_i\neq q_i\),如果 \(p_i\) 所在置换对应的点和 \(T\) 联通(不转),\(q_i\) 所在置换对应的点和 \(S\) 联通(也是不转) 就需要让答案减少,那么从 \(q\) 中点向 \(p\) 中点连边即可

  • \(p_i,q_i\neq i,p_i= q_i\),同时不转在上面刻画过了,同时转也类似,那么从 \(p\) 中点向 \(q\) 中点连边即可

跑最大流,时间复杂度 \(\Theta(n\sqrt n)\) ,当然需要当前弧优化

Code

const int N=4e5+10;
int n,p[N],q[N],idp[N],idq[N],tot;
int head[N],cur[N],dep[N],S,T,ecnt=1;
struct edge{int to,nxt,lim;}e[N<<2];
inline void adde(int u,int v,int w){
	e[++ecnt]={v,head[u],w}; head[u]=ecnt;
	return ;
}
inline void add(int u,int v,int w){return adde(u,v,w),adde(v,u,0);}
inline bool bfs(){
	queue<int> q; q.push(S); 
	rep(i,1,tot) cur[i]=head[i],dep[i]=0; 
	dep[S]=1;
	while(q.size()){
		int fr=q.front(); q.pop();
		for(int i=head[fr];i;i=e[i].nxt) if(e[i].lim){
			int t=e[i].to; if(dep[t]) continue;
			dep[t]=dep[fr]+1; q.push(t);
		}
	} return dep[T];
}
inline int dfs(int x,int in){
	if(x==T) return in; int out=0;
	for(int &i=cur[x];i;i=e[i].nxt) if(e[i].lim){
		int t=e[i].to; if(dep[t]!=dep[x]+1) continue;
		int res=dfs(t,min(in,e[i].lim));
		e[i].lim-=res; e[i^1].lim+=res;
		in-=res; out+=res;
		if(!in) break;
	}
	if(!out) dep[x]=0; return out;
}
int main() {
    n=read();
    for(int i=1;i<=n;++i) p[i]=read()+1;
    for(int i=1;i<=n;++i) q[i]=read()+1;
    S=++tot; T=++tot;
	for(int i=1;i<=n;++i) if(!idp[i]){
		int x=i;
		++tot;
		while(!idp[x]) idp[x]=tot,x=p[x];
	}
	for(int i=1;i<=n;++i) if(!idq[i]){
		int x=i;
		++tot;
		while(!idq[x]) idq[x]=tot,x=q[x];
	}
	int ans=n;
    for (int i=1;i<=n;++i){
	    if(p[i]==i||q[i]==i){
			if(p[i]==i&&q[i]==i){
				--ans;
				continue;
			}
			if(p[i]==i) add(idq[i],T,1);
        	if(q[i]==i) add(S,idp[i],1);
		}else{
			if(p[i]!=q[i]) add(idq[i],idp[i],1);
        	else add(idq[i],idp[i],1),add(idp[i],idq[i],1);
		}
	}
	while(bfs()) ans-=dfs(S,2*n);
    print(ans);
	return 0;
}

标签:int,lim,置换,Permutations,Two,dep,res,AGC038F,neq
来源: https://www.cnblogs.com/yspm/p/AGC038FTutorial.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有