Color
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 10277 | Accepted: 3348 |
Description
Beads of N colors are connected together into a circular necklace of N beads (N<=1000000000). Your job is to calculate how many different kinds of the necklace can be produced. You should know that the necklace might not use up all the N colors, and the repetitions that are produced by rotation around the center of the circular necklace are all neglected.
You only need to output the answer module a given number P.
You only need to output the answer module a given number P.
Input
The first line of the input is an integer X (X <= 3500) representing the number of test cases. The following X lines each contains two numbers N and P (1 <= N <= 1000000000, 1 <= P <= 30000), representing a test case.
Output
For each test case, output one line containing the answer.
Sample Input
5 1 30000 2 30000 3 30000 4 30000 5 30000
Sample Output
1 3 11 70 629
题目大意:用n个颜色涂n圆环,求旋转后不同的方案数%p。
学会polya后的第一题,要好好写题解啊
首先,根据polya定理,可以推出一个式子
ans=(1/n)*Σ(n^[gcd(n,i)])%p。
这玩意要%p,但是p不保证为质数,但是1/n可以乘到里面约掉,式子变为:
ans=Σ(n^[gcd(n,i)-1])%p。
然后这题的n是1e9,就很气...
试着将上式继续简化。
考虑到gcd(n,i)只有n^(1/2)个。
设旋转i的循环节长度为L,则L=n/(gcd(n,i))=>n/L=gcd(n,i)
设gcd(n,i)=g,则有n=L*g。
设i=g*t,则gcd(n,i)=gcd(L*g,t*g)=g
显然只有当gcd(L,t)=1时成立,且t<=L,所以gcd(n,i)=g=n/L的个数有phi(L)个。
枚举L,暴力算欧拉函数即可
代码:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#define ll long long
#define N 200020
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
bool vis[N];
int prime[N],cnt;
int cas,n,mod;
void init()
{
for(int i=2;i<N;i++)
{
if(!vis[i])prime[++cnt]=i;
for(int j=1;j<=cnt;j++)
{
long long tmp=(ll)prime[j]*i;
if(tmp>=N)break;vis[tmp]=1;
if(i%prime[j]==0)break;
}
}
}
ll qm(int a,int b)
{
ll ret=1,t=a;
while(b)
{
if(b&1)ret=ret*t%mod;
t=t*t%mod;b>>=1;
}return ret;
}
ll ans;
int phi(int t)
{
int ret=t;
for(int j=1;(ll)prime[j]*prime[j]<=t;j++)
{
if(t%prime[j])continue;
int s=t/prime[j];
ret=(ret-ret/prime[j]);
while(t%prime[j]==0)t/=prime[j];
}if(t>1)ret=(ret-ret/t);
return ret;
}
/*
1
1000000000 30000
*/
int main()
{
cas=read();init();
while(cas--)
{
n=read(),mod=read();
int nn=sqrt(n);ans=0;
for(int t=1;t*t<=n;t++)
{
if(n%t)continue;
int nt=n/t-1;
ans=(ans+phi(t)%mod*qm(n,nt)%mod)%mod;
int s=n/t,ns=n/s-1;
if(s!=t)ans=(ans+phi(s)*qm(n,ns)%mod)%mod;
}printf("%lld\n",ans);
}
}