2020牛客暑期多校训练营第二场Just Shuffle


Just Shuffle


原题传送门
题目大意:
给定大小为n的排列A和整数k(1≤n≤10^5 ,10^8 ≤k≤ 10^9,k为质数).。求出一个排列置换P,使得在执行k次排列置换P后,会将排列{1,2,3,…,n}变为A。请输出{1,2,3,…,n}在执行一次排列置换P后的结果。如果有多个解,输出任意一个即可。
样例输入:

3 998244353
2 3 1

样例输出:

3 1 2

题解:
首先把A的所有环求出来。不妨设这些环的大小为R1,R2,R3…Rc。因为k是大质数,所以可以对每一个i求一个invi=k^-1(mod Ri),这样的话只需要把A中的第i个环转个invi次,就可以得到一个合法解。
时间复杂度O(n)
代码:

#include
using namespace std;
const int MAXN=1e6+5;
int n,k,x,y,tim,tar,xx,yy,len;
int now[MAXN],p[MAXN],vis[MAXN],pw[MAXN],ans[MAXN];
void exgcd(int a,int b)
{
	if(!b)
	{
		x=1;
		y=0;
		return;
	}
    exgcd(b,a%b);
    xx=y;
    yy=x-(a/b)*y;
    x=xx;
    y=yy;
}
int getinv(int a,int b)
{
	exgcd(b,a);y%=b;
	if(y<0) y+=b;
	return y;
}
void findcycle(int x)
{
	do
	{
		vis[x]=1;
		now[++len]=x;
		x=p[x];
	}while(!vis[x]);}
int main()
{
	scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    	scanf("%d",p+i);
    for(int i=1;i<=n;i++)
    	if(!vis[i])
    		{
    			len=0;
    			findcycle(i);
            	tim=getinv(k%len,len);
            	tar=1;
            	for(int j=1;j<=len;j++)
            	{
            		pw[j]=now[tar];
                	tar=(tar+tim-1)%len+1;
            	}
            	pw[len+1]=pw[1];
            	for(int j=1;j<=len;j++)
            		ans[pw[j]]=pw[j+1];
        }
        for(int i=1;i<=n;i++)
        	printf("%d ",ans[i]);
}

置换群详解请点击这里置换群详解

你可能感兴趣的:(2020牛客暑期多校训练营第二场Just Shuffle)