poj Color

Color
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 4295 Accepted: 1437

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
用到Polya定理,但是求数据范围很大,表示压力很大;主要是浪费在求gcd(i,n)上面了,我的超时代码:
#include <cstdlib>
#include <iostream>
#include <cstdio>

__int64 n,p;
using namespace std;
int prime[360000],num;
bool isprime[360000];

void getprime()
{
    prime[0]=2;
    prime[1]=3;
    num=2;
    memset(isprime,1,sizeof(isprime));
    for(int i=5;i<360000;i++)
    {
        if(isprime)
        {
            prime[num++]=i;
            for(int j=2*i;j<360000;j+=i)
              isprime[j]=0;           
        }        
    }     
}
__int64 pow(__int64 a,__int64 b)
{
    __int64 temp=a,ans=1;
    while(b)
    {
        if(b&1)  ans*=temp%p;
        temp=(temp*temp)%p;
        b>>=1;        
    }
    return ans%p;        
}

__int64 phi(__int64 x)
{
     __int64 ans=x;
    for(int i=0;prime[i]*prime[i]<=x;i++)
     {
        if(x%prime[i]==0)
        {
            ans=ans/prime[i]*(prime[i]-1);
            while(x%prime[i]==0) x/=prime[i];          
        }           
     }      
     if(x!=1) ans=ans/x*(x-1);
     return ans%p; 
}
int main(int argc, char *argv[])
{
    int t;
    getprime();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%I64d%I64d",&n,&p);
        __int64 ans=0;
        for(__int64 i=1;i*i<=n;i++)
        {
           if(i*i==n)
           {
               __int64 e=phi(i)%p;
               __int64 d=pow(n,n/i-1);          
               ans+=(e*d)%p;
               ans%=p;
           }
           else  if(n%i==0)  
           {
               __int64 e=phi(i)%p;
               __int64 d=pow(n,n/i-1);          
               ans+=(e*d)%p;
               ans%=p;
               e=phi(n/i)%p;
               d=pow(n,i-1);
               ans+=(e*d)%p;
               ans%=p;      
           }       
        }
        printf("%I64d\n",ans%p);
    }      
    system("PAUSE");
    return EXIT_SUCCESS;
}
不知道为什么超时,呜呜。。先贴这吧学习了如果给出一个很大的数n,想要求比n小且与n最大公约数是x的个数是phi(n/x);例如n=10时,与gcd(10,i)==2(i<10),i=2,4,6,8个数就是
phi(10/2)(1,2,3,4)

ac代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

int p[31000], notp[31000], len = 0;
int n, yu;

void prime() {
    memset(notp,0,sizeof(notp));
    for (int i = 2; i < 31000; ++i) {
        if (notp[i] == 0) {
            p[len++] = i;
        }
        for (int j = 0; p[j]*i < 31000 && j < len; ++j) {
            notp[i*p[j]] = 1;
            if (i % p[j] == 0) {
                break;
            }
        }
    }
}

int phi(int n) {
    int temp = n;
    for (int i = 0; i < len && p[i]*p[i] <= temp; ++i) {
        if (temp % p[i] == 0) {
            n -= n/p[i];
            do {
                temp /= p[i];
            }while (temp % p[i] == 0);
        }
    }
    if (temp != 1) {
        n -= n/temp;
    }
    return n%yu;
}

int cal(int m) {
    int ans = 1;
    int s = n%yu;
    int temp = m;
    while (temp > 0) {
        if (temp&1) {
            ans = (ans * s) % yu;
        }
        s = (s*s)%yu;
        temp >>= 1;
    }
    return ans;
}

int main() {
    prime();
    int ca;
    scanf("%d", &ca);
    while (ca--) {
        scanf("%d %d", &n, &yu);
        int res = 0;
        for (int i = 1; i*i <= n; ++i) {
            if (i*i == n) {
                res = (res + phi(i)*cal(i-1))%yu;
            }
            else if (n%i == 0){
                res = (res + phi(i)*cal(n/i-1) + phi(n/i)*cal(i-1))%yu;
            }
        }
        printf("%d\n", res);
    }
    return 0;
}


posted on 2011-10-26 19:07  Goal  阅读(187)  评论(0编辑  收藏  举报

导航