poj 2154 color——polya
这道题wa到我快吐了……主要是因为计算欧拉函数的时候是先乘再除的,因该反过来,但是不知道这样为什么会wa,还有就是素数筛写搓了,标程的素数筛改成我的就wa了……
这道题n很大,我们套用polya公式的时候就不能枚举i了,只能反过来枚举循环的长度L
证明就不说了,别的解题报告都有……
对于每一个长度L,都有若干i使得gcd(n,i)=n/L,那么在polya公式里面,n^gcd(n,i)就有euler(L)个。因为L|n,所以只用枚举到L*L<n
后来才发现p不是素数,所以在除总数n的时候不可以用素数取逆方法直接算,就用的标程的方法,如下注释。
还有就是,现在还不知道哪里应该取模哪里不应该取模,哪里应该强制类型转换……很纠结啊………………………………
上代码:
a27400 | 2154 | Accepted | 948K | 1313MS | G++ | 1476B | 2011-08-24 14:54:54 |
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
int isprime[50001];
int prime[8001];
int tot;
void getprime() //以后就用这个素数筛模版好了……
{
for(int i=2;i<=50000;i++)if(!isprime[i])
{
prime[tot++]=i;
for(int j=1;j*i<=50000;j++)
{
isprime[i*j]=1;
}
}
tot--;
}
int euler(int n)
{
int i;
int _n=n;
int total=n;
for(i=0;i<=tot&&prime[i]*prime[i]<=n;i++)
{
if(n%prime[i]==0)
{
total=total/prime[i]*(prime[i]-1);
while(_n%prime[i]==0)
{
_n/=prime[i];
}
}
}
if(_n!=1)
{
total=total/_n*(_n-1);
}
return total;
}
int quickmod(int a,int n,int p)
{
if(n==0)
return 1%p;
if(n==1)
return a%p;
a%=p;
long long ans=quickmod(a,n/2,p)%p;
ans=ans*ans%p;
if(n&1)
ans=ans*a%p;
return (int)ans%p;
}
int main()
{
int Case;
getprime();
scanf("%d",&Case);
int n,p;
while(Case--)
{
scanf("%d %d",&n,&p);
int ans=0,i;
for(i=1;i*i<n;i++)
if(n%i==0)
{
ans=(ans+euler(i)%p*quickmod(n,n/i-1,p)+euler(n/i)%p*quickmod(n,i-1,p))%p;;//这里的i-1代表已经除以整个置换数n了,原本是expmod(n,i),最后要除以n的
}
if(i*i==n)
ans=(ans+euler(i)*quickmod(n,i-1,p))%p;
cout<<ans<<endl;
}
return 0;
}