poj 2154 polya定理+优化

#include <stdio.h>
#include <string.h>
#define INF 40000
int mod,n;
int f[INF];
int e[INF];//保存sqrt(n),一下的素数,用以计算i的个数
void init()
{
    int i,j,k=0;
    f[0]=f[1]=1;
    for(i=2;i<INF;i++)
    {
        if(f[i]==0)
        e[k++]=i;
        for(j=i*i;j<INF;j=j+i)
        f[j]=1;
    }
    //for(i=0;i<10;i++)
    //printf("%d\n",e[i]);
}
int find(int t)//找到符合条件的i的个数,即小于t且与t互质的个数
{
    int i,k;
    k=t;
    if(t==1)
    return 1;
    for(i=0;e[i]*e[i]<=t;i++)
    {
        if(t%e[i]==0)
        {
            k=k-k/e[i];
            while(t%e[i]==0)
            t=t/e[i];
            if(t==1)
            break;
        }
    }
    if(t!=1)
    k=k-k/t;
    return k;
}
int pows(int a,int b)  //快速幂
{
    int s=1;
    a=a%mod;
    while(b)
    {
        if(b&1)
        s=(s*a)%mod;
        b=b>>1;
        a=(a*a)%mod;
    }
    return s;
}
int main()
{
    init();
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&mod);
        int i,j,k,s=0,p,q;
        for(i=1;i*i<n;i++) //枚举循环长度,即n/gcd(n,i);
        {
            if(n%i==0)
            {
                p=pows(n,i-1);//直接除掉|G|=n
                q=find(n/i)%mod;//与n/i互质的个数
                //printf("%d\n",q);
                s=(s+(p*q)%mod)%mod;
                p=pows(n,n/i-1);//直接除掉|G|=n
                q=find(i)%mod;  //与i互质的个数
                //printf("%d\n",q);
                s=(s+(p*q)%mod)%mod;
            }
        }
        if(i*i==n)
        {
            p=pows(n,i-1);
            q=find(i)%mod;
            s=(s+(p*q)%mod)%mod;
        }
        printf("%d\n",s);
    }
    return 0;
}
//n个点,m个颜色
//枚举L=n/gcd(n,i),计算有多少个i符合条件
//设a=n/L=gcd(n,i);
//设i=a*t,则当且仅当gcd(L,t)=1时,
//gcd(n,i)=gcd(a*l,a*t)=a;
//其中t<L,1<=i<=n
//公式为1/|G|*(∑颜色数^循环数)

你可能感兴趣的:(Polya)