題目連結: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 }