POJ 2409 Let it Bead:置换群 Polya定理
题目链接:http://poj.org/problem?id=2409
题意:
有一串n个珠子穿起来的项链,你有k种颜色来给每一个珠子染色。
问你染色后有多少种不同的项链。
注:“不同”的概念是指无论怎样旋转或翻转项链,都与之前的不同。
题解:
本题用到了置换的相关知识:
(1)Burnside引理:
等价类数目 = 所有C(f)的平均值 (C(f)为置换f的不动点数目)
(2)置换f可以分解成m(f)个循环的乘积,假设涂k种颜色:
C(f) = k^m(f)
(3)Polya定理:(综上)
等价类数目 = 所有k^m(f)的平均数
考虑两种操作,旋转和翻转:
(1)旋转:
先假定所有的旋转都是顺时针(逆时针也一样)。
那么对于旋转这个操作,总共有n个置换:
不旋转(旋转0格)、顺时针旋转1格(1个珠子的距离)、2格、3格...n-1格。
所以现在要算的就是每个置换f的m(f),然后使用Polya定理。
旋转i格:m(f) = gcd(n,i)
所以sum += ∑( k^gcd(n,i) ) (0<=i<=n-1)
(2)翻转:
有两种情况,n为奇数或偶数。
1.偶数:
共有n个对称轴,也就是有n个置换。
I. 其中,n/2个对称轴不穿过珠子。这种置换的m(f) = n/2 。
所以sum += (n/2) * (k^(n/2))
II.另外n/2的对称轴恰好经过2颗珠子。这种置换的m(f) = n/2 - 1 。
所以sum += (n/2) * (k^(n/2-1))
综上:sum += (n/2) * ( k^(n/2) + k^(n/2-1) )
2.奇数:
共有n个对称轴,也就是有n个置换。并且每个对称轴恰好经过一颗珠子。
所有置换的m(f) = (n-1)/2
所以sum += n * ( k^((n-1)/2) )
呼。。。两种操作讨论完了。
因为两种操作总共有2*n个置换。
所以呢。。。
答案是:sum/(2*n) ヾ(๑╹◡╹)ノ"
AC Code:
1 // num of equivalence class = average C(f) 2 // C(f) = k ^ m(f) -> num of fixed points 3 // m(f) = circle num in each permutation 4 5 #include <iostream> 6 #include <stdio.h> 7 #include <string.h> 8 #define MAX_N 40 9 10 using namespace std; 11 12 int n,t; 13 int POW[MAX_N]; 14 15 int gcd(int a,int b) 16 { 17 return b==0?a:gcd(b,a%b); 18 } 19 20 int main() 21 { 22 while(cin>>t>>n) 23 { 24 if(n==0 && t==0) break; 25 POW[0]=1; 26 for(int i=1;i<=n;i++) 27 { 28 POW[i]=POW[i-1]*t; 29 } 30 int sum=0; 31 // rotate 32 for(int i=0;i<n;i++) 33 { 34 sum+=POW[gcd(n,i)]; 35 } 36 // overturn 37 if(n&1) sum+=n*POW[(n+1)/2]; 38 else sum+=(n/2)*(POW[n/2+1]+POW[n/2]); 39 cout<<sum/(2*n)<<endl; 40 } 41 }