链接
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; } } } 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; }
|