题目:http://acm.hdu.edu.cn/showproblem.php?pid=5392
题意:至今没弄懂题意。按admin的意思猜的:求出每个循环的长度,然后求出这些长度的最小公倍数。结果%3221225473。
分析:首先求出每个循环的长度len,由于结果很大,用gcd求最小公倍数的时候不能直接模3221225473(模下gcd是不正确的......),可以将所有的长度len分解质因子,记录每种质因子的最大数量,,最后快速幂求结果。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> typedef long long LL; using namespace std; const LL mod = 3221225473; const int sz = 3e6+7; const int maxn = 4000; int prime[maxn],nprime,a[sz],f[sz]; bool isprime[maxn],visit[sz]; void doprime() { nprime=0; int i,j; for(i=1;i<maxn;i+=2) isprime[i]=true; isprime[1]=false; isprime[2]=true; for(i=2;i<maxn;i++) { if(isprime[i]) { prime[nprime++]=i; for(j=2*i;j<maxn;j+=i) isprime[j]=false; } } } void divide(int x) { int ret=0,cnt; for(int i=0;i<nprime;i++) { if(x%prime[i]==0) { x/=prime[i]; cnt=1; while(x%prime[i]==0) { x/=prime[i]; cnt++; } f[prime[i]]=max(f[prime[i]],cnt); if(x==1) break; } } if(x>1) f[x]=max(f[x],1); } int getlen(int x) { int ret=1,cur=a[x]; visit[x]=true; while(x!=cur) { visit[cur]=true; ret++; cur=a[cur]; } return ret; } LL mypow(int a,int n) { LL ret=1; while(n) { if(n&1) ret=ret*a%mod; n>>=1; a=a*a%mod; } return ret; } void solve() { LL ans=1; for(int i=0;i<sz;i++) if(f[i]) ans=ans*mypow(i,f[i])%mod; printf("%lld\n",ans); } int main() { doprime(); int ncase,n,i,j; scanf("%d",&ncase); while(ncase--) { scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&a[i]); memset(f,0,sizeof(f)); memset(visit,false,sizeof(visit)); for(i=1;i<=n;i++) if(!visit[i]) divide(getlen(i)); solve(); } return 0; }
时间: 2024-10-11 01:27:59