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.
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个顶点用n种颜色染色,问有多少种方案(答案mod p,且可由旋转互相得到的算一种)
题解:
根据Polya定理我们可以得知答案为
如果数据范围小的话,就是很简单的求项链总数的脑残题(因为只考虑旋转)。
但是由于数据范围的限制,我们不能直接枚举去求,因此我们需要对原式进行化简(感觉有点像莫比乌斯反演)。
(不想自己写了,就搬了网上的解析(手动滑稽))
剩下的就好办了,我们先预处理求出一部分质数,然后我们再在O(sqrt(n))范围内去枚举就行了。
求phi(n)的模板我们也有,因此答案很容易就出来。
不过注意一下,求n的d-1次幂时要用快速幂求。
还有最后要特判一下 i*i==n 的情况
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#define rp(i, s, t) for (i = s; i <= t; i++)
#define RP(i, s, t) for (i = t; i >= s; i--)
#define ll long long
#define ull unsigned long long
using namespace std;
inline int read()
{
int x = 0, t = 1;
char ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-')
ch = getchar();
if (ch == '-')
t = -1, ch = getchar();
while (ch <= '9' && ch >= '0')
x = x * 10 + ch - 48, ch = getchar();
return x * t;
}
inline void write(int x)
{
char F[200];
int tmp = x > 0 ? x : -x;
if (x < 0)
putchar('-');
int cnt = 0;
while (tmp > 0)
{
F[cnt++] = tmp % 10 + '0';
tmp /= 10;
}
while (cnt > 0)
putchar(F[--cnt]);
}
int n,p;
const int N=1e5+7;
int visited[N],prime[N];
int tot;
void init()//预处理求出一部分的质数
{
memset(visited,0,sizeof visited);
tot=0;
int i;
rp(i,2,N-1){
if(!visited[i]){
prime[tot++]=i;
for(int j=i+i;j<N;j+=i)
visited[j]=1;
}
}
}
ll phi(ll n)//求n得欧拉函数的值
{
ll res=n;
for(int i=0;prime[i]*prime[i]<=n;i++){
if(n%prime[i]==0){
res=res-res/prime[i];
while(n%prime[i]==0) n/=prime[i];
}
}
if(n>1) res=res-res/n;
return res%p;
}
ll quick_mod(ll a,ll b)//快速幂
{
ll res=1;
while(b){
if(b&1) res=(res*a)%p;
a=(a*a)%p;
b>>=1;
}
return res%p;
}
int main()
{
init();
int T = read();
while (T--){
n=read(),p=read();
ll ans=0;
int i;
for(i=1;i*i<=n;i++){
if(i*i==n)//i*i==n的时候特判
ans=(ans+phi(i)*1ll*quick_mod(n,i-1)%p)%p;
else if(n%i==0)//如果i时n的约数,那么n/i也是n的约数,因此我们可以一次求两个。
ans=(ans+phi(n/i)*1ll*quick_mod(n,i-1)%p+phi(i)*1ll*quick_mod(n,n/i-1)%p)%p;
}
printf("%lld\n",ans%p);
}
return 0;
}