题目大意:给定一个长度为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;
}