http://acm.hdu.edu.cn/showproblem.php?pid=5392
题意:给一个置换群,求从(1,2,…,n)最少置换多少次后能回到(1,2,…,n)。
很显然是一个求最小公倍数的题。
知识点:在同一个轮换中,每个元素都是经过同样次数才能变回原来的元素。因此每个轮换只要求一次就可以。
然后就是利用质因数分解,求出每个质因数的最大次数幂,这些质因数的最大幂次的乘积即为答案。
不知道为什么如果用筛法求出1-3e6的所有质因数会TLE。。
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 3e6 + 5;
typedef long long ll;
const ll mod = 3221225473;
int a[maxn];
int vis[maxn], pCount[maxn];
ll qpow(ll a, ll b) {
ll res = 1;
while (b){
if (b & 1)res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res % mod;
}
int main(void) {
int T, n;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
pCount[i] = vis[i] = 0;
}
for (int i = 1; i <= n; i++) {
if (vis[i])continue;
vis[i] = 1;
int x = a[i];
int num = 1;
while (!vis[x]) {
vis[x] = 1;
x = a[x];
num++;
}
for (int j = 2; j * j <= num; j++) {
if (num % j != 0)continue;
int k = 0;
while (num % j == 0)num /= j, k++;
pCount[j] = max(pCount[j], k);
}
if (num != 1)pCount[num] = max(pCount[num], 1);
}
ll ans = 1;
for (int i = 2; i <= n; i++) {
if (!pCount[i])continue;
ans = ans * qpow((ll)i, (ll)pCount[i]) % mod;
}
printf("%lld\n", ans);
}
return 0;
}