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<bits/stdc++.h>
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]);
}
置换群详解请点击这里置换群详解