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;
}