ARC 124 D Yet Another Sorting Problem 题解

Description

给定一个长度为 N + M N+M N+M 的排列。

你每次可以选择前 N N N 个数中的一个以及后 M M M 个数中的一个并将它们交换。

你需要求出,至少需要多少次交换操作才能使得排列变为 1 , 2 , 3 , ⋯   , N + M 1,2,3,\cdots,N+M 1,2,3,,N+M

Solution

下面,为方便叙述,令位置不超过 N N N左边,否则为右边

假设我们可以交换同属一边的数,那么这就成为了一道裸题: 从 i i i p i p_i pi 连边,得到了一张每个点的入度以及出度均为 1 1 1 的图。考虑其每一个连通块(显然是个环),并交换环上相邻的位置即可。总操作次数为 N + M − K N+M-K N+MK,其中 K K K 表示连通块的个数。

加入只能交换左右边的限制怎么办呢?我们依然按照 i → p i i \to p_i ipi 的方式建图。考虑每一个连通块,若它跨越了左边和右边,那么它必然可以 S − 1 S-1 S1 次交换中被还原,其中 S S S 表示连通块的大小。特别的,若它只属于左边或只属于右边,那么上述结论不成立。

令只属于左边的连通块有 X X X 个,只属于右边的连通块有 Y Y Y 个。不妨设 X < Y X<Y X<Y。我们可以将左边的前 Y Y Y 个与右边的两两配对并进行操作,且每次操作次数均为 S S S,其中 S S S 表示混合连通块的大小(先随意交换一个位置,然后接下来每次都可以恰好复原一个位置,最后一次可以复原两个位置, 1 + ( S − 1 ) = S 1+(S-1)=S 1+(S1)=S)。对于那 Y − X Y-X YX 个失配的,我们从异侧硬搞过来一个位置与它配对并进行操作。分析一下这两种的优劣——对于混合连通块而言,若 S = x + y S=x+y S=x+y,我们默认操作次数是 x − 1 + y − 1 x-1+y-1 x1+y1 然而这里是 x + y x+y x+y,所以总数要加上 2 2 2。对于单个连通块而言,令其大小为 x x x,我们找过来了一个使得 S = x + 1 S=x+1 S=x+1,然而我们默认是 x − 1 x-1 x1,所以总数也要加上 2 2 2

综上所述,答案为 N + M − K + 2 max ⁡ ( X , Y ) N+M-K+2\max(X,Y) N+MK+2max(X,Y)

时间复杂度 O ( n ) O(n) O(n),本题被解决。

Code

#include <bits/stdc++.h>
using namespace std;
const int maxl=200005;

int read(){
    
    
	int s=0,w=1;char ch=getchar();
	while (ch<'0'||ch>'9'){
    
    if (ch=='-')  w=-w;ch=getchar();}
	while (ch>='0'&&ch<='9'){
    
    s=(s<<1)+(s<<3)+(ch^'0');ch=getchar();}
	return s*w;
}
int n,m,len,k,x,y;
int a[maxl],fa[maxl],cntl[maxl],cntr[maxl];

int Find(int x){
    
    
	if (x==fa[x])  return x;
	else return fa[x]=Find(fa[x]);
}

signed main(){
    
    
	n=read(),m=read();len=n+m;
	for (int i=1;i<=len;i++){
    
    
		a[i]=read(),fa[i]=i;
		if (i<=n)  cntl[i]=1;
		else cntr[i]=1;
	}
	for (int i=1;i<=len;i++){
    
    
		int fu=Find(i),fv=Find(a[i]);
		if (fu!=fv){
    
    
			fa[fu]=fv;
			cntl[fv]+=cntl[fu];
			cntr[fv]+=cntr[fu];
		}
	}
	for (int i=1;i<=len;i++){
    
    
		if (i==Find(i)){
    
    
			k++;
			if (cntl[i]+cntr[i]==1)  continue;
			if (cntr[i]==0)  x++;
			if (cntl[i]==0)  y++;
		}
	}
	cout<<len-k+2*max(x,y)<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Cherrt/article/details/119201483