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.
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; }