Hdu 5392 Infoplane in Tina Town

链接

Infoplane in Tina Town

题意

给定n个数,第i个数为a表示将第i个数变为a,问最少经过多少次变换可使这n个数从
{1,2,…n}再变为{1,2,…n}

分析

置换群求最小置换周期
对于每个元素可求出其最小置换周期,整个序列的最小置换周期为所有元素周期的最小公倍数
但是求最小公倍数lcm(a,b)时如果先求最大公约数gcd(a,b),再用a/gcd(a,b)*b会超时
可以用分解质因子的方法
先把这几个数的质因数写出来,最小公倍数等于它们所有的质因数的乘积(如果有几个质因数相同,则比较两数中哪个数有该质因数的个数较多,乘较多的次数)

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include<stdio.h>
#include<string.h>
typedef long long LL;
const LL mod=3221225473LL;
const int N=3000100;
struct stu{
int num,per;
}a[N];
int n,cnt[N];
bool vis[N];
void calPer()//计算每个元素的周期
{

memset(vis,false,sizeof(vis));
for(int i=1;i<=n;i++){
if(!vis[i]){
vis[i]=true;
int t=a[i].num;
int cnt=1;
while(t!=i){
vis[t]=true;
cnt++;
t=a[t].num;
}
a[i].per=cnt;
//求i的循环节,i再次变为i经过的数周期都相同
//相同数的最小公倍数相同,只需算一次就可以,否则会超时
//t=a[i].num;
// while(t!=i){
//a[t].per=cnt;
//t=a[t].num;
//}
}
}
}
void calFactor()
{

memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++){
int temp=a[i].per;
for(int j=2;j<=a[i].per;j++){
int num=0;
while(temp%j==0){
num++;
temp/=j;
}
if(num>cnt[j])
cnt[j]=num;
}
}
}
LL powMod(LL a,LL b)
{

LL ans=1;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
int main()
{

int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i].num);
a[i].per=-1;
}
calPer();
calFactor();
LL ans=1;
for(int i=2;i<=n;i++)
ans=(ans*powMod(i,cnt[i]))%mod;
printf("%I64d\n",ans);
}
return 0;
}