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