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;
}
posted @ 2020-07-27 10:31  BakaCirno  阅读(135)  评论(0编辑  收藏  举报