置换群
对于一个大小为$n$的循环,走$k$步之后分解成$gcd(n,k)$个循环
现在相当于我们知道$a = gcd(n,k)$和$k$,分别合成最初的循环。
问题在于找出$n$,我们构造一个最小的$n$,这个$n$满足包含所有在$a$中出现的质因子的次数加上质因子在$k$中的出现次数
那么暴力枚举因数即可
然后合并循环,按照手上模拟即可。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e6 + 5; int n, l, top; vector<int> *st[maxn]; int vis[maxn], b[maxn], tmp[maxn], ans[maxn]; bool cmp(vector<int> *a, vector<int> *b) { return a -> size() < b -> size(); } int cal(int n) { // puts("in"); int ret = 1, t = l; for(int i = 2; i * i <= n; ++i) if(n % i == 0) { while(n % i == 0) { n /= i; ret *= i; } while(t % i == 0) { t /= i; ret *= i; } } if(n != 1) { ret *= n; while(t % n == 0) { t /= n; ret *= n; } } return ret; } int main() { scanf("%d%d", &n, &l); for(int i = 1; i <= n; ++i) scanf("%d", &b[i]); for(int i = 1; i <= n; ++i) if(!vis[i]) { int p = i; st[++top] = new vector<int>; while(!vis[p]) { st[top] -> push_back(p); vis[p] = 1; p = b[p]; } } sort(st + 1, st + top + 1, cmp); for(int i = 1; i <= top; ) { int t = cal(st[i] -> size()); int len = __gcd(t, l); // printf("size = %d t = %d len = %d ", st[i] -> size(), t, len); for(int j = 0; j < len; ++j) for(int k = 0; k < st[i + j] -> size(); ++k) tmp[(j + 1LL * l * k) % t] = (*st[i + j])[k]; for(int j = 0; j < t; ++j) ans[tmp[j]] = tmp[(j + 1) % t]; i += len; // puts("fffffff"); } for(int i = 1; i <= n; ++i) printf("%d ", ans[i]); return 0; }