CF1411F - The Thorny Path

CF1411F - The Thorny Path

题目大意

给定一个置换\(p_i\),求通过最少次交换\(p_i,p_j\),使得最终的置换中所有置换环\(size\)乘积最大


分析

一个常规结论:

对于\(n(n\ge 3)\)的拆分\(n=\sum_{i=1}^m a_i\),最大化\(\prod a_i\),最优情况下

1.\(n\mod 3=0\)\(a_i=3\)

2.\(n\mod 3=2\)\(i<m,a_i=3 ; a_m=2\)

3.\(n\mod 3=1\)\(i<m,a_i=3 ; a_m=4\)\(i<m-1,a_i=3 ;a_{m-1}=a_m=2\)

简要证明


容易发现对于任意\(n\),最终\(a_i\)的方案是\(O(1)\)的,设当前置换环为\(b_i\),我们需要操作\(b_i\)变成\(a_i\)

1.一次在同环交换可以分裂一个环

2.一次异环交换合并两个环

所以原问题实际上就是最少次数分裂合并\(b_i\)

对于\(n\mod 3=0\)\(n\mod 3=2\)的情况,如果当前\(b_i\ge 3\),可以一直不停分裂

最终剩下的就是\(b'_i=1\)或者\(b'_i=2\)

对于\(n\mod 3=2\)的情况,优先从中取出一个2<或者由两个1合并得到一个2

剩下的优先合并1和2,然后剩下的自己合并

\(n\mod 3=1\)同理,但是\(a_i=4\)的情况也不能分裂,需要拿出来特殊处理

const int N=1e6+10,P=1e9+7;

int n,m;
int Pow[N];
int A[N],L[N],C,R[N],D;
int vis[N];

int Calc(int c1,int c2){
	int t=min(c1,c2),ans=t;
	c1-=t,c2-=t;
	if(c1) ans+=c1/3*2;
	if(c2) ans+=c2;
	return ans;
}

int Calc(int c1,int c2,int c4){ return c4+Calc(c1+c4,c2); }

int main(){
	rep(i,*Pow=1,N-1) Pow[i]=1ll*Pow[i-1]*3%P;
	rep(_,1,rd()) {
		n=rd();
		rep(i,1,n) A[i]=rd(),vis[i]=0;
		C=0;
		rep(i,1,n) if(!vis[i]) {
			int c=0;
			for(int j=i;!vis[j];j=A[j]) c++,vis[j]=1;
			L[++C]=c;
		}
		if(n%3==0) {
			printf("%d ",Pow[n/3]);
			int ans=0;
			rep(i,1,C) {
				while(L[i]>3) L[i]-=3,ans++;
				if(L[i]==3) L[i]=0;
			}
			int c1=0,c2=0;
			rep(i,1,C) if(L[i]==1) c1++;
			else if(L[i]==2) c2++;
			ans+=Calc(c1,c2);
			printf("%d\n",ans);
			continue;
		}

		if(n%3==2) {
			printf("%d ",Pow[n/3]*2%P);
			int cnt=n/3,ans=0;
			rep(i,1,C) {
				while(cnt && L[i]>3) L[i]-=3,cnt--,ans++;
				if(L[i]==3 && cnt) L[i]=0,cnt--;
			}
			int c1=0,c2=0;
			rep(i,1,C) if(L[i]==1) c1++;
			else if(L[i]==2) c2++;
			if(c2) c2--;
			else c1-=2,ans++;
			ans+=Calc(c1,c2);
			printf("%d\n",ans);
			continue;
		}
		printf("%lld ",Pow[(n-4)/3]*4ll%P);
		int cnt=(n-4)/3,c3=0,ans=0;
		rep(i,1,C) {
			while(cnt && L[i]>4) L[i]-=3,cnt--,ans++;
			if(L[i]==3 && cnt) L[i]=0,cnt--;
		}
		int c1=0,c2=0,c4=0;
		rep(i,1,C) if(L[i]==1) c1++;
		else if(L[i]==2) c2++;
		else if(L[i]==3) c3++;
		else if(L[i]==4) c4++;
		if(c3) ans++;
		else {
			int w=1e9;
			if(c4) cmin(w,Calc(c1,c2,c4-1));
			if(c1>=4) cmin(w,Calc(c1-4,c2,c4)+2);
			if(c2>=2) cmin(w,Calc(c1,c2-2,c4));
			if(c1>=2 && c2)  cmin(w,Calc(c1-2,c2-1,c4)+1);
			ans+=w;
		}
		printf("%d\n",ans);
	}
}
posted @ 2021-05-20 08:23  chasedeath  阅读(77)  评论(0编辑  收藏  举报