2020牛客暑期多校训练营(第二场) J-Just Shuffle【置换群】
题意
已知\(\{1,2,...,n\}\)按照\(P\)经过\(k\)次变化之后得到\(A\),现在给定\(A\)与\(k\),求\(\{1,2,...,n\}\)按照\(P\)经过\(1\)次变化之后的结果\(B\)。
题解
主要的知识点是置换群,当然我一点都不了解,所以这道题直接GG。
可以得知,\(B^k=A\),根据置换群与逆元可知,\(A^{k^{-1}}=B\)。设\(A\)中所有环是\(r_1,r_2,...,r_m\),本来\(k^{-1}\)应该是\(lcm\{|r_1|,|r_2|,...,|r_m|\}\)下的逆元,但其实可以对每个环分开考虑,所以对于每个环\(r_i\),求出\(k\)在模\(|r_i|\)下的逆元\(inv_i\),然后对环上每个点变换\(inv_i\)次就行了。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10;
int n,a[N],ans[N],vis[N],k;
vector<int> vec;
void dfs(int u){
if(vis[u]) return;
vis[u]=1;
vec.push_back(u);
dfs(a[u]);
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int w=1;w<=n;w++){
if(vis[w]) continue;
vec.clear();
dfs(w);
int siz=vec.size(),inv;
for(int i=1;i<=siz;i++)if(1ll*k*i%siz==1) inv=i;
for(int i=0;i<siz;i++) ans[vec[i]]=vec[(i+inv)%siz];
}
for(int i=1;i<=n;i++) printf("%d ",ans[i]);
return 0;
}