/* 题目要求:给出两个整数n和p,代表n个珠子,n种颜色,要求不同的项链数,并对结果mod(p)处理。 置换只有旋转一种方式,那么共有n个置换 基本知识:环的个数为gcd(n , i) , 长度L=n / gcd(n , i) 其中 i 为转的位子数 普通求法: ∑n^( gcd(n,i) ) 0<=i<n 复杂度过高 优化:枚举环的长度L 枚举优化: L可以从1取到sqrt(n) ,因为L|n , n/L | n 对于每个L,我们再看有几个i满足条件 n/L = gcd(n , i) 那么令 a=n/L = gcd(n , i) , 再设i = at 那么当且仅当gcd(L,t)=1时候,才有gcd(n,i) = a 显然满足条件的i的个数就是t的个数也就是phi(L) 那么最后统计一下就是 ∑(phi(L) * N^(L-1) ) % p (L即枚举值) */ #include<iostream> #include <stdlib.h> #include <algorithm> #include <stdio.h> #include<vector> using namespace std; const int MAXN=1000000000; int isprime[50001]; int prime[8001]; int num,n,p; void getprime() { num=0; for(int i=2;i<=50000;i++)if(!isprime[i]) { prime[num++]=i; for(int j=1;j*i<=50000;j++) { isprime[i*j]=1; } } } int euler(int x) { int res=x; for(int i=0;i<num&&prime[i]*prime[i]<=x;i++) { if(x%prime[i]==0) { res=res/prime[i]*(prime[i]-1); while(x%prime[i]==0) { x/=prime[i]; } } } if(x>1) res=res/x*(x-1); return res; } int expmod(int a,int b,int mod) { int ret=1; a=a%mod; while(b>0) { if(b&1)ret=(ret*a)%mod; a=(a*a)%mod; b>>=1; } return ret; } int main() { int Case; getprime(); scanf("%d",&Case); while(Case--) { scanf("%d%d",&n,&p); int ans=0,i; for(i=1;i*i<n;i++)if(n%i==0) { ans=(ans+euler(i)%p*expmod(n,n/i-1,p)+euler(n/i)%p*expmod(n,i-1,p))%p;;//这里的i-1代表已经除以整个置换数n了,原本是expmod(n,i),最后要除以n的, } if(i*i==n) ans=(ans+euler(i)*expmod(n,i-1,p))%p; cout<<ans<<endl; } return 0; }