题意:n个珠子围成一圈,有n种颜色,旋转后相同的视为同一种方案.
n<=1e9,P<=3e4,问不同的上色方案数并将结果余P.
旋转后相同视为同一种,用Polya定理来计数
确定置换群,计算循环节个数,代入公式即可.
本题置换群为旋转1.2...n格,置换i的循环节个数为gcd(n,i)
由于n<=1e9 不能直接带入 把gcd相同的分为一类 对于 每一类n^d,求出有多少个i满足,gcd(n,i)=d -> gcd(n/d,i/d)=1 即欧拉函数(n/d)
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;
typedef long long ll;
const int N=2e5+20;
const int M=6e4;
int n,p;
int pri[N+20],vis[N+20];
void init()
{
memset(vis,0,sizeof(vis));
for(int i=2,j=0;i<=M;i++)
{
if(!vis[i])
{
pri[j++]=i;
for(int j=i+i;j<=M;j+=i)
vis[j]=1;
}
}
}
int phi(int n)
{
int res=n;
for(int i=0;pri[i]*pri[i]<=n;i++)
{
if(n%pri[i]==0)
{
res=res/pri[i]*(pri[i]-1);
while(n%pri[i]==0)
n/=pri[i];
}
}
if(n>1)
res=res/n*(n-1);
return res;
}
int powmod(int n,int m,int p)
{
int s=1;
n%=p;
while(m)
{
if(m&1)
s=(s*n)%p;
n=(n*n)%p;
m>>=1;
}
return s;
}
int main()
{
init();
int t;
cin>>t;
while(t--)
{
scanf("%d%d",&n,&p);
int ans=0;
for(int d=1;d*d<=n;d++)
{
if(n%d==0)
{
//×î´ó¹«Ô¼ÊýΪdʱ,gcd(n,i)=d,gcd(n/d,i/d)=1Âú×ãÌõ¼þµÄiÓÐphi[n/d]¸ö
int res=(phi(n/d)%p*powmod(n,d-1,p))%p;
ans=(ans+res)%p;
if(d*d==n) continue;
res=(phi(d)%p*powmod(n,n/d-1,p))%p;
ans=(ans+res)%p;
}
}
cout<<ans<<endl;
}
return 0;
}