poj2154Color polya定理+欧拉函数优化

没想到贱贱的数据居然是错的。。搞得我调了一中午+晚上一小时(哦不d飞LJH掉RP毕竟他是BUFF)结果重判就对了五次。。

回归正题,这题傻子都看得出是polya定理(如果你不是傻子就看这里),还没有翻转,就一个旋转,结果我就欢快的打完交上去了。傻子都知道会TLE,n<=1e9啊,O(n)都原地爆炸,那怎么办。。。一脸懵逼(然后就膜题解了)

可以发现,这题公式就是sigma(gcd(k,n))(k=1~n),然后该怎么优化呢,我(??)发现gcd(k,n)里面肯定有一些k和n的gcd是相同的,那我们设n=i*gcd,k=j*gcd,那i肯定和j互质并且1<=j<=i,而且可以发现,gcd(i*gcd,j*gcd)=gcd,只要知道j有多少个,就让power(n,n/i)乘上这个个数,那gcd=n/i的所有情况就都解决了,那具体j有多少个呢?显而易见(??)就是欧拉函数值(然而我不会)了,那我们O(sqrt(n))枚举i,然后就可以得出gcd,然后就可以求出欧拉函数值,那就是phi(i)*power(n,n/i)

#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
bool v[1100000];
int pr,prime[1100000];
void linear_prime()
{
    memset(v,true,sizeof(v));
    for(int i=2;i<=1000000;i++)
    {
        if(v[i]==true)prime[++pr]=i;
        for(int j=1;j<=pr&&i*prime[j]<=1000000;j++)
        {
            v[i*prime[j]]=false;
            if(i%prime[j]==0)break;
        }
    }
}
int n,mod;
int power(int A,int k)
{
    int ans=1;A%=mod;
    while(k!=0)
    {
        if(k%2==1)ans=(ans*A)%mod;
        A=(A*A)%mod;k/=2;
    }
    return ans;
}
int phi(int x)//求欧拉函数值,即j的种数 
{
    int ans=x;
    for(int i=1;prime[i]*prime[i]<=x;i++)
    {
        if(x%prime[i]==0)
        {
            ans=ans-ans/prime[i];
            while(x%prime[i]==0)x/=prime[i];
        }
    }
    if(x!=1)ans=ans-ans/x;
    return ans%mod;
}
int main()
{
    linear_prime();
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&mod);
        int ans=0;
        //设n=i*gcd 而 k=j*gcd,用欧拉函数将所有j的值求出 
        for(int i=1;i*i<=n;i++)
        {
            if(n%i==0)
            {
                ans=(ans+phi(i)*power(n,n/i-1))%mod;//循环节为gcd
                if(i*i!=n)ans=(ans+phi(n/i)*power(n,i-1))%mod;
                //这里两个power为什么要-1?由于要%mod,所以求值的时提早将/G(G=n)给做了 
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
posted @ 2017-09-26 19:52  AKCqhzdy  阅读(288)  评论(0编辑  收藏  举报