题目链接:http://poj.org/problem?id=2154
题意:n 种颜色的珠子构成一个长为 n 的环,每种颜色珠子个数无限,也不一定要用上所有颜色,旋转可以得到状态只算一种,问有多少种不同的情况。
思路:polya 模板,不过数据比较大,需要用欧拉优化。
代码:
1 #include<iostream> 2 #include <stdlib.h> 3 #include <algorithm> 4 #include <stdio.h> 5 #include<vector> 6 using namespace std; 7 8 const int MAXN = 1e5 + 10; 9 int isprime[MAXN]; 10 int prime[MAXN]; 11 int num, n, p; 12 13 void getprime(void){ 14 num = 0; 15 for(int i = 2; i <= MAXN; i++)if(!isprime[i]){ 16 prime[num++] = i; 17 for(int j = 1; j * i <= MAXN; j++){ 18 isprime[i * j] = 1; 19 } 20 } 21 } 22 23 int euler(int x){ 24 int res = x; 25 for(int i = 0; i < num && prime[i]*prime[i] <= x; i++){ 26 if(x % prime[i] == 0){ 27 res = res / prime[i] * (prime[i] - 1); 28 while(x % prime[i] == 0){ 29 x /= prime[i]; 30 } 31 } 32 } 33 if(x > 1) res = res / x * (x - 1); 34 return res; 35 } 36 37 int expmod(int a, int b, int mod){ 38 int ret = 1; 39 a = a % mod; 40 while(b > 0){ 41 if(b & 1)ret = (ret * a) % mod; 42 a = (a * a) % mod; 43 b >>= 1; 44 } 45 return ret; 46 } 47 48 int main(void){ 49 int t; 50 getprime(); 51 scanf("%d", &t); 52 while(t--){ 53 scanf("%d%d", &n, &p); 54 int ans = 0, i; 55 for(i = 1; i * i < n; i++)if(n % i == 0){ 56 ans = (ans + euler(i) % p * expmod(n, n / i - 1, p) + euler(n / i) % p * expmod(n, i - 1, p)) % p;; //这里的i-1代表已经除以整个置换数n了,原本是expmod(n,i),最后要除以n的, 57 } 58 if(i * i == n) 59 ans = (ans + euler(i) * expmod(n, i - 1, p)) % p; 60 cout << ans << endl; 61 } 62 return 0; 63 }