前置知識
1.羣的定義
給定一個集合 和 集合上的二元運算,並滿足以下四個條件:
- 封閉性:。
- 結合律:。
- 單位元:。
- 逆元:。
則稱在運算下十一個羣,簡稱是一個羣,一般簡寫爲.。可以是任何運算,如果是,就稱爲加法羣,是,就稱爲乘法羣。如果羣中的元素是有限的,就稱爲有限羣,否則稱爲無限羣,有限羣中的元素個數稱爲有限羣的階。
2.羣的運算
對於,對於的子集,定義,簡寫爲,簡寫爲。
對於的子集,定義,簡寫爲。
對於的子集,記
定理1:若是羣,則對於任一。
定理2:若是羣,是的非空子集,並且也是羣,那麼稱爲的子羣。
根據 定理2 可以判斷子集是否爲一個子羣:等價於是的子羣。
3.置換
個元素之間的一個置換
表示 被到中的某個數取代, 被到中的某個數取代,…,直到 被到中的某個數取代,且互不相同。
4.置換羣
置換羣的元素是置換,運算是置換的連接。例如:
可以驗證置換羣滿足羣的 4 個條件。
下面舉個題目的例子:
He‘s Circles(SGU294)
題意: 有一個長度爲N的環,上面寫着’X’和’E’,問本質不同的環有多少種。(N不超過200000)。
SGU已經掛掉了,所以不再用這題作爲例題。
主要是用來練習找一下本題中的置換羣{轉0格,轉1格,轉2格,…,轉n-1格}
轉 0 格:
轉 1 格:
轉 2 格:
轉 n-1 格:
5.循環
先介紹一個循環的概念:
稱爲 階循環。每個置換都可以寫若干互不相交的循環的乘積,兩個循環和 互不相交是指。例如:
置換的循環節數是上述表示中循環的個數。例如的循環節數爲 3。
BurnSide 引理
BurnSide 引理是羣論中的一個重要結論,在組合數學中可用於計算等價類的個數,常用於Polya計數。
1.主要內容:
用 表示在置換 下不變的元素的個數(不動點數)。表示本質不同的方案數(等價類的個數), 是置換羣中置換的個數 。
對於上述 He‘s Circles(SGU294) 例子中的情況,一共有4個置換:
因爲每個點只有兩個狀態"X"和"E",所以一共有種情況。
- 所有方案在置換下都不變,
- XXXX 和 EEEE 在置換下不變,
- XXXX 和 EEEE 及 XEXE 和 EXEX 在置換下不變,
- XXXX 和 EEEE 在置換下不變,
綜上,
下面主要介紹一個經典的案例:方陣着色問題
對於的方陣用黑白兩種顏色塗色,問能得到多少種不同的圖像?經過旋轉使之吻合的兩種方案,算是同一種方案。(圖片來自百度百科)
從圖中我們可以發現 案例3,案例4,案例5,案例6 可以通過旋轉變爲一種,我們就可以把(3,4,5,6)稱爲等價類(具體概念之後會有)。
那麼一共有多少等價類呢?
- 1
- 2
- 3,4,5,6
- 7,8,9,10
- 11,12
- 13,14,15,16
所以我們可以知道等價類數目就是6,仔細想一想,我們可以發現這個例子就和我們上面 SGU例子中,N = 4 是一樣的。
對於四個置換{逆時針旋轉0°,逆時針旋轉90°,逆時針旋轉180°,逆時針旋轉270°},其不動點數分別爲16, 2, 4, 2。所以等價類數目爲(16+2+4+2)/4 = 6。
2.補充的兩個概念
等價類: 設是中的某個元素,在置換羣作用下的軌跡上所有元素的集合
舉個例子:
在方陣着色問題中,
- 方案 1 在{逆時針旋轉0°,逆時針旋轉90°,逆時針旋轉180°,逆時針旋轉270°}的四個置換下的都是方案1,所以
- 方案 3 ,在{逆時針旋轉0°,逆時針旋轉90°,逆時針旋轉180°,逆時針旋轉270°}的四個置換下分別是方案3,4,5,6所以。
不動置換類:** 設是中的某個元素,在置換羣作用下使 的位置保持不變的置換的全體。
舉個例子:
- 對於上圖的方案 11,{逆時針旋轉0°,逆時針旋轉90°,逆時針旋轉180°,逆時針旋轉270°}的四個置換下分別變成了 方案11 ,方案12,方案11,方案12。所以只有第一個置換和第三個置換保證了位置不變
。
公式
總結一下:
BurnSide引理就是非等價着色數等於置換羣中保持不變的着色的平均數,
等價類 = 各個置換下不動點個數的和 / 置換羣中的置換個數。
Polya定理
Polay定理實際上是BurnSide引理的具體化,因爲BurnSide中 並不是很好計算,搜索的話要大量的時間,所以Polya 定理提供了計算不動點的具體方法,達到快速求出的目的。
假設一個置換有 個循環,易知每個循環對應的所有位置顏色需一致,而任意兩個循環之間選什麼顏色互不影響。因此,如果有m種可選顏色,則該置換對應的不動點個數爲 。用其替換BurnSide引理中的,得到等價類數目爲:
爲第個置換的循環個數。
總結一下:
Polya定理就是用(染色顏色^循環節數)求和 來替代 Burnside中的不動點個數
各個置換下不動點個數的和 = 染色顏色^循環節數的和
所以我們解決 求等價類 個數的問題就轉化成了兩個主要問題:
- 構造置換羣
- 計算置換羣中每個置換的循環節數 並求和。
下面是一道經典例題:
POJ 1286 Necklace of Beads
題意
給出三種顏色紅綠藍,對一串n個小球的環染色,環可以旋轉和翻轉,問最終可能有多少不同的染色方案。
思路
按照我們上面描述的那樣,我們先解決第一個問題:構造我們的置換羣。
分析題目,我們可以有 n個小球,3種顏色,我們可以通過旋轉來找到本質相同的染色方案,但這樣就結束了嗎? 並沒有,我們來看下面這個例子:
面對圖中的情況,我們通過旋轉是沒有辦法找到兩個本質相同的方案,所以還需要考慮翻轉的問題。
到此我們知道,可以把我們的置換主要分爲兩類:
- 旋轉 : 旋轉 個小球的距離,那麼會得到 的置換方案,共有種。 旋轉 個小球,我們的第 個小球就轉到了 第 lab[j] 個位置 。lab[j] = (i + j) % n + 1;
- 翻轉:其實就是將對稱的位置交換,第 j 個 位置第 n + 1 - j 個位置交換。
解決了置換羣的構造問題,那麼下一步就是 計算出循環節數的問題。
首先使用一種樸素的計算循環節數的方法,就是直接模擬我們手算循環節數的過程。
樸素循環節求法:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#define ll long long
using namespace std;
const int N = 30;
int lab[N];
bool vis[N] = {0};
int n;
//快速冪
ll qpow(ll a, ll b){
ll res = 1;
while(b){
if(b & 1){
res *= a;
}
a *= a;
b >>= 1;
}
return res;
}
//計算循環節數
ll get_loop(){
ll cnt = 0;
memset(vis,0,sizeof(vis));
for(int i = 1; i <= n; i++){
if(vis[i]) continue;
cnt++;
int j = i;
do{
vis[j] = true;
j = lab[j];
}while(!vis[j]);
}
return cnt;
}
int main(){
while(cin>>n){
//printf("No smoking!");
if(n == -1) break;
ll ans = 0;
if(n < 1){
puts("0");
continue;
}
for(int i = 0; i < n; i++){
//旋轉
for(int j = 1; j <= n; j++) lab[j] = (i + j) % n + 1;
ans += qpow(3,get_loop());
//翻轉
for(int j = 1; j <= n / 2; j++) swap(lab[j],lab[n + 1 - j]);
ans += qpow(3,get_loop());
}
printf("%lld\n",ans/(n*2));
}
return 0;
}
前人總結了一些關於循環節的一些結論:
①旋轉。有n種置換,分別是1次旋轉1個珠子,2個,3個…n個。對於1次旋轉i個珠子,我們要求出循環節數可以先求出循環長度,一個位置置換x次之後回到原位,所以x=ny/i,要使x儘量小且爲整數那麼ny只能是lcm(n,i),於是循環長度爲lcm(n,i)/i,那麼循環節數爲總長除以循環長度,n/(lcm(n,i)/i)=gcd(n,i)【n*i/gcd(n,i)=lcm(n,i)】。所以1次旋轉i個珠子的循環節數爲gcd(n,i)。
②翻轉。對於奇偶性分類討論。
(1)n爲奇數。對於每個點作爲對稱軸左右翻轉,則共n個置換,循環節數(n+1)/2。
(2)n爲偶數。
a.對於對稱的兩個點作爲對稱軸左右翻轉。n/2個置換,循環節數(n+2)/2。
b.對於兩個點中間的空格作爲對稱軸左右反轉,n/2個置換,循環節數n/2。
則共n個置換。
所以不論奇偶總置換數爲2n,答案爲sum/2n。
.
———— 以上結論來自博客https://www.cnblogs.com/Sakits/p/6985058.html
下面給出一些簡要證明:
①旋轉
設當前的位置是 ,我們一次旋轉 個位置,假設我們旋轉了 次到了原位置。
那麼我們就有
兩邊同時減去,可以得到
可以知道 ,又因爲 ,但是我們求的是循環節長度,即 需要最小,又因爲 是常量,那麼我們當然取 和 的最小公倍數了。
又因爲
可以得到
因爲循環節的長度爲,又一共有個元素,且這個元素對稱,那麼顯然循環節個數就是。
②翻轉
(1)奇數個點
奇數個點,對稱軸肯定是經過某一個點,(下圖的藍點),那麼,每一對 對稱的點 就形成了一個循環節 。
以下圖爲例,藍色點爲對稱的點,綠點和紅點是一個循環節,黃色和橙色是一個循環節 ,藍色是不動點 本身是一個循環節。所以一共是個循環節。
(2)偶數個點
偶素有兩種對稱的可能
- 對稱軸過其中兩點
有 個不動點,剩下的 每兩個點成一個循環節,共個。 - 對稱軸在兩點間的空格
每兩個點成一個循環節,共個。
下面是運用結論求法
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#define ll long long
using namespace std;
const int N = 30;
int lab[N];
bool vis[N] = {0};
int n;
//最大共約數
ll gcd(ll a, ll b){
return b == 0 ? a : gcd(b,a % b);
}
//快速冪
ll qpow(ll a, ll b){
ll res = 1;
while(b){
if(b & 1){
res *= a;
}
a *= a;
b >>= 1;
}
return res;
}
int main(){
while(cin>>n){
//printf("No smoking!");
if(n == -1) break;
ll ans = 0;
if(n < 1){
puts("0");
continue;
}
//旋轉置換
for(int i = 1; i <= n; i++)
ans += qpow(3,gcd(i,n));
//對稱置換
if(n&1) {
ans+=qpow(3,n/2+1)*n;
} else {
ans+=qpow(3,n/2+1)*(n/2);
ans+=qpow(3,n/2)*(n/2);
}
printf("%lld\n",ans/(n*2));
}
return 0;
}