Description
Beads of red, blue or green colors are connected together into a circular necklace of n beads ( n < 24 ). If the repetitions that are produced by rotation around the center of the circular necklace or reflection to the axis of symmetry are all neglected, how many different forms of the necklace are there?
Input
The input has several lines, and each line contains the input data n. -1 denotes the end of the input file.
Output
The output should contain the output data: Number of different forms, in each line correspondent to the input data.
Sample Input
4 5 -1
Sample Output
21 39
Source
1、题目类型:Polya定理、组合数学、置换群。
2、解题思路:Polya定理:(1)设G是p个对象的一个置换群,用k种颜色突然这p个对象,若一种染色方案在群G的作用下变为另一种方案,则这两个方案当作是同一种方案,这样的不同染色方案数为:;
(2)置换及循环节数的计算方法:对于有n个位置的手镯,有n种旋转置换和n种翻转置换.
对于旋转置换: c(fi) = gcd(n,i) i为一次转过i颗宝石( i = 0 时 c=n;);
对于翻转置换:如果n为偶数:c(f) = n/2 的置换有n/2个;
c(f) = n/2+1 的置换有n/2个;
如果n为奇数:c(f) = n/2+1.
3、注意事项:注意对于翻转置换过程中对于奇偶数情况的区分处理。
相同的gcd合并在一起计算:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<map> 5 #include<set> 6 #include<vector> 7 using namespace std; 8 #define ll long long 9 ll pow_mod(ll a,ll i){ 10 if(i==0) 11 return 1; 12 ll t=pow_mod(a,i/2); 13 ll ans=t*t; 14 if(i&1) 15 ans=ans*a; 16 return ans; 17 } 18 19 20 21 vector<ll> divisor(ll n){ 22 vector<ll> res; 23 for(ll i=1;i*i<=n;i++){ 24 if(n%i==0){ 25 res.push_back(i); 26 if(i*i!=n){ 27 res.push_back(n/i); 28 } 29 } 30 } 31 return res; 32 } 33 ll eular(ll n){ 34 ll res=1; 35 for(ll i=2;i*i<=n;i++){ 36 if(n%i==0){ 37 n/=i,res*=i-1; 38 while(n%i==0){ 39 n/=i; 40 res*=i; 41 } 42 } 43 } 44 if(n>1) res*=n-1; 45 return res; 46 } 47 ll polya(ll m,ll n){ 48 //map<ll,ll> primes = prime_factor(n); 49 vector<ll> divs = divisor(n); 50 ll res=0; 51 for(ll i=0;i<divs.size();i++){ 52 ll euler=eular(divs[i]); 53 res+=euler*pow_mod(m,n/divs[i]); 54 } 55 res/=n; 56 return res; 57 } 58 int main() 59 { 60 ll n,m=3; 61 while(~scanf("%I64d",&n) && n!=-1){ 62 if(n==0){ 63 puts("0"); 64 continue; 65 } 66 ll count=polya(m,n)*n;//旋转情况 67 if(n&1){//奇数 68 count+=n*pow_mod(m,n/2+1);//翻转情况 69 } 70 else{//偶数 71 count += (pow_mod(m, n / 2 + 1) + pow_mod(m, n / 2)) * (n / 2);//翻转情况 72 } 73 count/=2*n; 74 printf("%I64d ",count); 75 } 76 return 0; 77 }
附上大神代码:
相同的gcd合并在一起计算:
1 #include <iostream> 2 #include <map> 3 #include <vector> 4 using namespace std; 5 6 #define LL long long 7 8 inline LL power(LL p, LL n) 9 { 10 LL sum = 1; 11 while (n) 12 { 13 if (n & 1) 14 sum *= p; 15 p *= p; 16 n /= 2; 17 } 18 return sum; 19 } 20 21 //************************************ 22 // Method: divisor 23 // FullName: divisor 24 // Access: public 25 // Returns: vector<int> 约数 26 // Qualifier: 约数枚举 27 // Parameter: const int & n 目标数n 28 //************************************ 29 vector<int> divisor(const int& n) 30 { 31 vector<int> res; 32 for (int i = 1; i * i <= n; ++i) 33 { 34 if (n % i == 0) 35 { 36 res.push_back(i); 37 if (i != n / i) 38 { 39 res.push_back(n / i); 40 } 41 } 42 } 43 44 return res; 45 } 46 47 //************************************ 48 // Method: prime_factor 49 // FullName: prime_factor 50 // Access: public 51 // Returns: map<int, int> 52 // Qualifier: 整数分解 53 // Parameter: int n 54 //************************************ 55 map<int, int> prime_factor(int n) 56 { 57 map<int, int> res; 58 for (int i = 2; i * i <= n; ++i) 59 { 60 while (n % i == 0) 61 { 62 ++res[i]; 63 n /= i; 64 } 65 } 66 if (n != 1) 67 { 68 res[n] = 1; 69 } 70 return res; 71 } 72 73 LL polya(const int& m, const int& n) 74 { 75 map<int, int> primes = prime_factor(n); 76 vector<int> divs = divisor(n); 77 LL res = 0; 78 for (int i = 0; i < divs.size(); ++i) 79 { 80 // 求divs[i]的欧拉函数值 81 LL euler = divs[i]; 82 for (map<int, int>::iterator it = primes.begin(); it != primes.end(); ++it) 83 { 84 int p = it->first; 85 if (divs[i] % p == 0) euler = euler / p * (p - 1); 86 } 87 88 res += euler * power(m, n / divs[i]); 89 } 90 91 // 最后除以n 92 res /= n; 93 return res; 94 } 95 96 ///////////////////////////SubMain////////////////////////////////// 97 int main(int argc, char *argv[]) 98 { 99 #ifndef ONLINE_JUDGE 100 freopen("in.txt", "r", stdin); 101 freopen("out.txt", "w", stdout); 102 #endif 103 int n; const LL m = 3; 104 while (~scanf("%d", &n) && n != -1) 105 { 106 if (n == 0) 107 { 108 puts("0"); 109 continue; 110 } 111 112 LL count = polya(m, n) * n; 113 if (n & 1) 114 count += n * power(m, n / 2 + 1); 115 else 116 count += (power(m, n / 2 + 1) + power(m, n / 2)) * (n / 2); 117 count /= 2 * n; 118 printf("%lld ", count); 119 } 120 #ifndef ONLINE_JUDGE 121 fclose(stdin); 122 fclose(stdout); 123 system("out.txt"); 124 #endif 125 return 0; 126 }
还有一种暴力求法:
1 #include <iostream> 2 using namespace std; 3 4 #define LL long long 5 6 int gcd(int a, int b) 7 { 8 return b == 0 ? a : gcd(b, a % b); 9 } 10 11 LL power(LL p, LL n) 12 { 13 LL sum = 1; 14 while (n) 15 { 16 if (n & 1) 17 sum *= p; 18 p *= p; 19 n /= 2; 20 21 } 22 return sum; 23 } 24 25 ///////////////////////////SubMain////////////////////////////////// 26 int main(int argc, char *argv[]) 27 { 28 #ifndef ONLINE_JUDGE 29 freopen("in.txt", "r", stdin); 30 freopen("out.txt", "w", stdout); 31 #endif 32 int n; const LL m = 3; 33 while (~scanf("%d", &n) && n != -1) 34 { 35 if (n == 0) 36 { 37 puts("0"); 38 continue; 39 } 40 LL count = 0; 41 for (int i = 1; i <= n; ++i) 42 count += power(m, gcd(i, n)); 43 if (n & 1) 44 count += n * power(m, n / 2 + 1); 45 else 46 count += n / 2 * (power(m, n / 2 + 1) + power(m, n / 2)); 47 count /= n * 2; 48 printf("%lld ", count); 49 } 50 #ifndef ONLINE_JUDGE 51 fclose(stdin); 52 fclose(stdout); 53 system("out.txt"); 54 #endif 55 return 0; 56 }