AGC031D A Sequence of Permutations

AGC031D

有个排列的数列,\(a_1=p\)\(a_2=q\)

\(f(p,q)\)表示第\(p_i\)个数为\(q_i\)的排列,即\(f(p,q)_{p_i}=q_i\)

\(a_n=f(a_{n-2},a_{n-1})\)

问第\(a_k\)是多少。

\(n\le 10^5,k\le 10^9\)


一开始思考的时候置换的定义姿势不对……直接把题目的那个操作定义为置换的乘法了……

我们如此定义置换:\(f=pq\),即\(f_i=p_{q_i}\)

那么\(a_n=a_{n-1}a_{n-2}^{-1}\)

把前面若干项写出来,会发现一个规律:设\(A=qp^{-1}q^{-1}p\),则\(a_n=Aa_{n-6}A^{-1}\)。可以归纳证明。

算出\(A\)的若干次方。可以直接快速幂,也可以把轮换找出来直接移动。


using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
int n,k;
int p[N],q[N],p_[N],q_[N],A[N];
void inv(int p_[],int p[]){
	static int r[N];
	for (int i=1;i<=n;++i)
		r[p[i]]=i;
	memcpy(p_,r,sizeof(int)*(n+1));
}
void multi(int f[],int p[],int q[]){
	static int r[N];
	for (int i=1;i<=n;++i)
		r[i]=p[q[i]];
	memcpy(f,r,sizeof(int)*(n+1));
}
void getpow(int p[],int k){
	static int vis[N],r[N],q[N];
	memset(vis,0,sizeof(int)*(n+1));
	for (int i=1;i<=n;++i)
		if (!vis[i]){
			int cnt=0;
			for (int x=i;!vis[x];x=p[x])
				vis[x]=1,q[cnt++]=x;
			for (int j=0;j<cnt;++j)
				r[q[j]]=q[(j+k)%cnt];
		}
	memcpy(p,r,sizeof(int)*(n+1));
}
int main(){
	freopen("in.txt","r",stdin);
	scanf("%d%d",&n,&k);
	for (int i=1;i<=n;++i)
		scanf("%d",&p[i]);
	for (int i=1;i<=n;++i)
		scanf("%d",&q[i]);
	inv(p_,p),inv(q_,q);
	memcpy(A,q,sizeof(int)*(n+1));	
	multi(A,A,p_),multi(A,A,q_),multi(A,A,p);
	int r=(k-1)%6;
	for (int i=0;i<r;++i){
		inv(p,p);
		multi(p,q,p);
		swap(p,q);
	}
	getpow(A,(k-1)/6);
	multi(p,A,p);
	inv(A,A);
	multi(p,p,A);
	for (int i=1;i<=n;++i)
		printf("%d ",p[i]);
	return 0;
}
posted @ 2020-09-14 18:51  jz_597  阅读(83)  评论(0编辑  收藏  举报