poj2154(polya定理+欧拉函数)

题目链接: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 }
View Code

 

posted @ 2017-11-01 21:40  geloutingyu  阅读(196)  评论(0编辑  收藏  举报