环+逆——牛客多校赛第二场J题

环+逆元

——牛客多校赛第二场J题

Given a permutation with size n and an integerk, you should find a permutation substitutionP that{1,2,⋯,n} will become {A}A after performing substitution P for exactly k times. Print the permutation after performing P for once on{1,2,⋯,n}. If there are multiple solutions, print any of them. If there is no solution, print “-1” in one line.
输入描述:
The first line contains two integersn,k (1≤n≤10^5,10 ^8 ≤k≤10 ^9).
The second line contains n integers,
It is guaranteed that k is a prime number.
输出描述:
If there exists solutions, print n integers in one line, or print “-1” in one line.

示例1
输入
3 998244353
2 3 1
输出
3 1 2

题解:题意真的不好理解,如果没学过离散的话就很难弄,他就是离散里面的置换,他每一次 操作相当于对着乘原来置换(置换的几次幂)。这里题意中A^k=B,现在已知B和k要求就是求出原来的A,我们就是求出B需要作用几次会得到A即(B的几次方等于A )我先设 B的Z次方等于A,B又等于A^k次方所以A的K*Z幂等于A,所以Z就是等于K关于每个环大小的逆是多少。所以求出每个环的大小并且每个让K取逆(欧几里得算法哦),分别求出逆的大小后环里一循环就好啦!

#include
using namespace std;
int a[500050],huan[500050],c,k,n,vis[500050];
void exgcd(int a,int b,int &x,int &y){
    if(!b) {x=1,y=0;return ;}
    exgcd(b,a%b,y,x);
    y-=a/b*x;
}
int main()
{
    while(~scanf("%d%d",&n,&k))
    {
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        int num=1;
        for(int i=1;i<=n;i++)
            if(vis[i]==0){
                vis[i]=1;
                int tmp=a[i];
                num=0;huan[num++]=i;//这里本来用num=1开始错了
                //但是后来一想,下面求解的是取模o,所以从0-num-1
                while(tmp!=i){
                    vis[tmp]=1;
                    huan[num++]=tmp;
                    tmp=a[tmp];
                }
                int x,y,t;
                exgcd(k%num,num,x,y);
                x=(x+num)%num;//这里就是求了K关于环大小的逆
                for(int i=0;i

你可能感兴趣的:(牛客,数论)