题目大意:给定一个长度为n的置换b和一个正整数k, 求一个置换a,使得ak=b

要做这个题首先我们需要知道ak是什么
想象一个长度为L的循环,如果我们将这个循环求k次方,我们将会得到Gcd(L,k)个长度为LGcd(L,k)的循环
那么现在我们将b分解成循环,假如现在我们得到了一个长度为L′的循环,那么由之前的结论可以得到L′=LGcd(L,k)
容易证明存在一个最小的L满足这个L是所有合法的L的约数,且这个L满足对于L′的任意一个质因子p,p在L中的次数等于p在L′中的次数加上p在k中的次数
于是我们找到这个最小的L,将LGcd(L,k)个长度为L′的循环合并成一个循环即可
BZ上没有SPJ,建议去main上交
回头写个SPJ去

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 1001001
using namespace std;
int n,k;
int a[M],ans[M];
bool v[M];
vector<int> *stack[M];int top;
bool Compare(vector<int> *v1,vector<int> *v2)
{
    return v1->size() < v2->size() ;
}
void Get_Circulation(int x,vector<int> *vec)
{
    while(1)
    {
        if(v[x]) return ;
        vec->push_back(x);
        v[x]=true;x=a[x];
    }
}
int Get_L(int x)
{
    int i,k=::k,re=1;
    for(i=2;i*i<=x;i++)
        if(x%i==0)
        {
            while(x%i==0)
                x/=i,re*=i;
            while(k%i==0)
                k/=i,re*=i;
        }
    if(x!=1)
    {
        re*=x;
        while(k%x==0)
            k/=x,re*=x;
    }
    return re;
}
int main()
{
    int i,j,k;
    cin>>n>>::k;
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(i=1;i<=n;i++)
        if(!v[i])
            Get_Circulation(i,stack[++top]=new vector<int>);
    sort(stack+1,stack+top+1,Compare);
    for(i=1;i<=top;)
    {
        static int a[M];
        int L=Get_L(stack[i]->size());
        int temp=__gcd(L,::k);
        for(j=0;j<temp;j++)
            for(k=0;k<(signed)stack[i+j]->size();k++)
                a[(j+(long long)k*::k)%L]=(*stack[i+j])[k];
        for(j=0;j<L;j++)
            ans[a[j]]=a[(j+1)%L];
        i+=temp;
    }
    for(i=1;i<=n;i++)
        printf("%d\n",ans[i]);
    return 0;
}