由Polya定理可得到最后结果等于1/N*∑N^gcd(i,n);
可是,N≤10^9,枚举i明显会超时,但gcd(i,n)最后得到的结果很少,最多1000多个,于是反过来枚举gcd(i,n)的值L,L即n的某个约数,那么我们需要找到0~n-1中有多少个数与n的约数是L,由扩展欧几里得可以知道,必然存在x,y使得
i*x+n*y=L,由于L是i,n最大公约数,所以可以变成(i/L)*x+(n/L)*y=1,同时mod(n/L),(i/L)*x≡1(mod n/L),即,要找与n/L互质的i/L有多少个,变成欧拉函数了!
于是,最后答案就变成了∑φ(n/L)*N^(L-1),dfs+快速幂取模搞定
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mr=100001;
bool notp[mr];
int pr[mr];
int pn,mod,n;
void getp()
{
memset(notp,0,sizeof(notp));
pn=0;
for(int i=2;i<mr;i++)
{
if(!notp[i])
pr[pn++]=i;
for(int j=0;j<pn&&i*pr[j]<mr;j++)
{
int k=i*pr[j];
notp[k]=1;
if(i%pr[j]==0)
break;
}
}
}
int fac[1025],tot[1025],num;
void div(int n)
{
num=0;
for(int i=0;i<pn&&pr[i]*pr[i]<=n;i++)
{
if(n%pr[i]==0)
{
tot[num]=0;
fac[num]=pr[i];
while(n%pr[i]==0)
{
n/=pr[i];
tot[num]++;
}
num++;
}
}
if(n>1)
{
fac[num]=n;
tot[num]=1;
num++;
}
}
int getphi(int n)
{
int tp=n;
for(int i=0;i<pn&&pr[i]*pr[i]<=n;i++)
{
if(n%pr[i]==0)
{
tp=tp/pr[i]*(pr[i]-1);
while(n%pr[i]==0)
n/=pr[i];
}
}
if(n>1)
tp=tp/n*(n-1);
return tp;
}
int mulmod(int a, int b)//a*b%m 避免高精度计算
{
a=a%mod,b=b%mod;
int re=0;
while(b)
{
if(b&1) re=(re+a)%mod;
a=(a<<1)%mod;
b>>= 1;
}
return re;
}
int fastmod(int a,int b)//a^b %m 注意可能要用long long时用long long
{
int re=1,y=a%mod;
for(;b;b>>=1,y=mulmod(y, y))
if(b&1)re=mulmod(y,re);
return re;
}
int ans;
void solve(int L)
{
int ph=getphi(n/L)%mod,po=fastmod(n%mod,L-1);
ans+=mulmod(ph,po);
if(ans>=mod)
ans-=mod;
}
void dfs(int k,int L)
{
if(k==num)
solve(L);
else
{
int tp=1;
dfs(k+1,L);
for(int i=1;i<=tot[k];i++)
{
tp*=fac[k];
dfs(k+1,L*tp);
}
}
}
int main()
{
getp();
int T;
for(scanf("%d",&T);T;T--)
{
scanf("%d%d",&n,&mod);
if(mod==1)
{
printf("0\n");
continue;
}
else if(n==1)
{
printf("1\n");
continue;
}
ans=0;
div(n);
dfs(0,1);
printf("%d\n",ans);
}
return 0;
}