poj 2154 Color(欧拉函数,快速幂,波利亚计数)

来源:互联网 发布:程序员的思维方式 编辑:程序博客网 时间:2024/05/18 00:06
Color
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 7458 Accepted: 2452

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

51 300002 300003 300004 300005 30000

Sample Output

131170629
本题只考虑旋转,不考虑翻转,因此置换群大小为N!ans = [N^gcd(1,N)+N^gcd(2,N)...+N^gcd(N,N)]/N;
=>ans = N^(gcd(1,N)-1)+N^(gcd(2,N)-1)...+N^(gcd(N,N)-1)这个时候我们就可以在运算时%P了。
难点1:如何提高求gcd(i,N)的效率?
    我们知道,如果用暴力的话肯定是超时的,因为N<=1000000000!
    但是,gcd(i,N)的数量是很少的,我们可以枚举,怎么枚举呢?只要枚举从[1,sqrt(N)]就行了,因为求出所有i∈[1,sqrt(N)]能够满足N%i==0,就可以求出所有j∈[sqrt(N),N]能够满足N%j==0,j=N/i。
    这样枚举的效率是sqrt(N)。ans = ∑sum[L]*N^(L-1),sum[L]为gcd(i,N)==L的个数。
难点2:如何求出gcd(i,N)==L时,i的个数?
    i=L*x , N=L*y,因为gcd(i,N)==L,所以x,y互质。反证法,如果x,y不互质,则gcd(i,N)!=L。
    因此,枚举L就可以求出y,然后求[1,y]与y互质的个数,这个可以用欧拉函数解决!
    欧拉函数的效率小于是sqrt(y)*log2(y).
难点3:如何求N^(gcd(i,N)-1)?
    如果用库函数pow会有精度损失,这肯定是不行的,如果自己用暴力写肯定会超时的,因为gcd(i,N)最大是1000000000。
    所以我们用快速幂求,效率是log2(N)<30.
卡过!
#include <iostream>#include <cstdio>using namespace std;#define ll long longll N , P;ll pow(ll C , ll t){//快速幂求C^tll ans = 1;while(t>0){if(t%2==1){ans = (ans*C)%P;}C = (C%P*(C%P))%P;t /= 2;}return ans%P;}ll Euler(int x){ll ans = 1;for(int i = 2; i*i <= x; i++){if(x%i == 0){ans = ans*(i-1)%P;x /= i;while(x%i==0){ans = ans*i%P;x /= i;}}}if(x > 1) ans = (ans%P)*((x-1)%P);return ans;}ll Polya(int Bean , int Color){//波利亚计数,Bean表示项链珠子个数,Color表示颜色种数ll ans = 0;for(int i = 1; i*i <= Bean; i++){if(Bean%i == 0){if(i != Bean/i){ans += (Euler(i)%P*pow(Color , Bean/i-1)%P)%P;ans += (Euler(Bean/i)%P*pow(Color , i-1)%P)%P;}else{ans += (Euler(i)%P*pow(Color , Bean/i-1)%P)%P;}ans = ans%P;}}return ans%P;}int main(){int T;cin >> T;while(T--){scanf("%lld%lld" , &N , &P);printf("%lld\n" , Polya(N , N));}return 0;}


0 0
原创粉丝点击