Color
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 11077 Accepted: 3589
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.
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,p。表示有n中颜色的珠子,串成一个n长度的手链,旋转相同视为同一种方案,输出不重复的方案数,答案%p。
思路:题意很简单,裸的Polya公式,按照以前的思路,只需要计算i=1~n时,n^(gcd(n,i)-1)即可,但是n<=1e9。光是遍历一遍都会炸,所以我们要考虑优化一下这个算法。
gcd(i,n)一定是n的因子,n的因子肯定不会太多,意味着很多gcd(n,i)都是相同的,如果我们能求出gcd相同的i的个数,那么就可以将算法优化到logn的复杂度。
优化过程:
设i=g*x
n=g*y
满足gcd(n,i)=g的条件显然是x,y互质,那么只要知道1~y中有多少个x与y互质即可。这里显然可以用欧拉函数优化。
AC代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<math.h>
#define met(s,k) memset(s,k,sizeof s)
#define scan(a) scanf("%d",&a)
#define scanl(a) scanf("%lld",&a)
#define scann(a,b) scanf("%d%d",&a,&b)
#define scannl(a,b) scanf("%lld%lld",&a,&b)
#define scannn(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define prin(a) printf("%d\n",a)
#define prinl(a) printf("%lld\n",a)
using namespace std;
typedef long long ll;
const int maxn=50000;
int isprime[maxn],prime[maxn],pcont,flen,factor[maxn],n,mod;
void init()//筛出素数便于求欧拉函数
{
for(int i=2; i<maxn; i++)
{
if(!isprime[i])
{
prime[pcont++]=i;
for(int j=2*i; j<maxn; j+=i)
isprime[j]=1;
}
}
}
void Dqfactor(int x )//这里我先对n进行了分解质因数,多此一举,反而怎加了复杂度
{
flen=0;
for(int i=0; prime[i]*prime[i]<=x&&x!=1; i++)
{
if(x%prime[i]==0)
{
factor[flen++]=prime[i];
while(x%prime[i]==0)x/=prime[i];
}
}
if(x!=1)factor[flen++]=x;
}
int euler(int x)//这里直接用素数去枚举因子即可,我是直接用分解质因数的因子去除的
{
int res=x;
for(int i=0;i<flen&&x!=1;i++)
{
if(x%factor[i]==0)
{
res=res/factor[i]*(factor[i]-1);
while(x%factor[i]==0)x/=factor[i];
}
}
return res%mod;
}
ll ksm(ll x,ll y)//配合快速幂使用,效果更佳
{
ll res=1;
x%=mod;
while(y)
{
if(y&1)res=res*x%mod;
y/=2;
x=x*x%mod;
}
return res;
}
int polya()
{
int ans=0;
for(int i=1; i*i<=n; i++)
{
if(n%i==0)
{
ans=(ans+euler(i)*ksm(n,n/i-1))%mod;
if(n/i!=i)ans=(ans+euler(n/i)*ksm(n,i-1))%mod;//对于两个因子都是i 的,显然只要一个即可
}
}
return ans;
}
int main()
{
init();
int t;
scan(t);
while(t--)
{
scann(n,mod);
Dqfactor(n);
prin(polya());
}
return 0;
}