题目链接:http://poj.org/problem?id=2154
题意:n 种颜色的珠子构成一个长为 n 的环,每种颜色珠子个数无限,也不一定要用上所有颜色,旋转可以得到状态只算一种,问有多少种不同的情况。
思路:polya 模板,不过数据比较大,需要用欧拉优化。
代码:
#include<iostream>
#include <stdlib.h>
#include <algorithm>
#include <stdio.h>
#include<vector>
using namespace std; const int MAXN = 1e5 + ;
int isprime[MAXN];
int prime[MAXN];
int num, n, p; void getprime(void){
num = ;
for(int i = ; i <= MAXN; i++)if(!isprime[i]){
prime[num++] = i;
for(int j = ; j * i <= MAXN; j++){
isprime[i * j] = ;
}
}
} int euler(int x){
int res = x;
for(int i = ; i < num && prime[i]*prime[i] <= x; i++){
if(x % prime[i] == ){
res = res / prime[i] * (prime[i] - );
while(x % prime[i] == ){
x /= prime[i];
}
}
}
if(x > ) res = res / x * (x - );
return res;
} int expmod(int a, int b, int mod){
int ret = ;
a = a % mod;
while(b > ){
if(b & )ret = (ret * a) % mod;
a = (a * a) % mod;
b >>= ;
}
return ret;
} int main(void){
int t;
getprime();
scanf("%d", &t);
while(t--){
scanf("%d%d", &n, &p);
int ans = , i;
for(i = ; i * i < n; i++)if(n % i == ){
ans = (ans + euler(i) % p * expmod(n, n / i - , p) + euler(n / i) % p * expmod(n, i - , p)) % p;; //这里的i-1代表已经除以整个置换数n了,原本是expmod(n,i),最后要除以n的,
}
if(i * i == n)
ans = (ans + euler(i) * expmod(n, i - , p)) % p;
cout << ans << endl;
}
return ;
}