POJ2154 Polya+欧拉函数

来源:互联网 发布:软件开发学费多少 编辑:程序博客网 时间:2024/05/18 03:01

首先声明一下,这题不是我自己做的。

可以说基本是拿了别人的东西,之所以写这篇文章一是为了理清自己的思路,二是将自己遇到的问题和大家分享。

虽说是第一个Polya的题目,还是感觉自己真的好水!!

参考:

http://blog.csdn.net/acdreamers/article/details/8656247

http://blog.csdn.net/wsniyufang/article/details/6671122

思路:

1、根据Polya原理:

其中:

L为染色方案计数,

Q为置换群,

q为置换群中的置换,

m为可染的颜色数,指数(rang ta(q),符号不会打,只能将就)为置换q的变换下的循环数。


2、推论:在n个格子中,顺时针旋转 i 个格子,循环个数为gcd(n,i),每个循环长度为n/gcd(n,i)。

也就是说,根据这条推论可以得到:L= 1/n * sum( m^gcd(n,i) );

但是,直接这样求得复杂度为O(n),而n<=1e9,是不可行的!!


3、优化(不是自己做的):

 

剩下的就是代码:




//2154_Color #include<cstdio>#include<cmath>#define N 1000000010<span style="color:#ff0000;">//必须为int ,否则超时!</span> typedef int LL;LL ans;int phi[36000]; LL pow(LL x,LL y,LL m){//x^y%mLL r1=1;<span style="color:#ff0000;">//必须取模,否则WA ! </span>x%=m;while(y){if(y&1)r1=r1*x%m;x=(x*x)%m;y=y>>1;}return r1;}void getPhi(){int n=sqrt(N);for(int i=2;i<=n;i++){if(!phi[i]){for(int j=i*i;j<=n;j+=i){phi[j]=1;}}}for(int i=2,j=0;i<=n;i++){if(!phi[i]){phi[j++]=i;}}}int Euler(int x){int r=x;for(int i=0;phi[i]*phi[i]<=x;i++){if(x%phi[i]==0) {r=r-r/phi[i];while(x%phi[i]==0) x/=phi[i];}}//!!if(x>1) r=r-r/x;return r;}int main(){int t;LL p,n;scanf("%d",&t);getPhi();while(t--){ans=0;scanf("%d%d",&n,&p);//solve()int i;for(i=1;i*i<n;i++){if(n%i==0){<span style="color:#ff0000;">//!!注意:如果i是n的约数,则n/i也是n的约数,也要做同样的处理! </span>ans=( ans+ (Euler(n/i)%p) * pow(n,  i-1,p) ) %p ;ans=( ans+ (Euler(i)  %p) * pow(n,n/i-1,p) ) %p ;}}if(i*i==n)ans=( ans+ (Euler(i)%p) * pow(n,i-1,p) ) %p ;printf("%d\n",ans);}return 0;}


0 0
原创粉丝点击