1. 程式人生 > 實用技巧 >polya定理

polya定理

設有\(n\)個物件,\(G\)是這\(n\)個物件上的置換群,用\(m\)種顏色塗染著\(n\)個物件,每個物件塗一種顏色,問有多少種染色方案

\[M = \frac{1}{|G|}\sum_{i = 1}^{|G|}m^{c(\sigma_i)} \]

\(G = {\sigma_1,\sigma_2,\dots,\sigma_k}\)\(c(\sigma_i)\)為置換\(\sigma_i\)的迴圈節數

集合\(G\)\(G\)上的二元運算,滿足下列條件稱為群:

  • 封閉性
  • 結合律
  • 有單位元
  • 有逆元

置換群

\([1,n]\)到自身\(1-1\)對映稱為\(n\)階置換。\([1,n]\)

目標集上的置換表示為

\[\sigma(1) = a_1,\sigma(2) = a_2\dots \sigma(n) = a_n \]

\(a_n\)\([1,n]\)中元的一個排列

舉個例子,這是個\(n = 5\)的5元置換,\(\sigma(1) = 3,\sigma(3) = 1\),構成迴圈,\(\sigma(4) = 4\),4的置換是本身,也是一個迴圈,所以也可以寫成\(\sigma = (1,3)(4)(2,5)\),一般一階輪換(4)不寫,\(\sigma = (1,3)(2.5)\)

正三角形

![114E8C20-99B6-41DB-988E-F314FA43C464](/Users/i/Library/Containers/com.tencent.qq/Data/Library/Application Support/QQ/Users/2287697454/QQ/Temp.db/114E8C20-99B6-41DB-988E-F314FA43C464.png)

旋轉0°:\(p1 = \begin{array}{l} \left(\begin{array}{l} 1&2&3\\ 1&2&3 \end{array}\right) \end{array}\)

旋轉120°:\(p2 = \begin{array}{l} \left(\begin{array}{l} 1&2&3\\ 2&3&1 \end{array}\right) \end{array}\)

旋轉240°:\(p3 = \begin{array}{l} \left(\begin{array}{l} 1&2&3\\ 3&1&2 \end{array}\right) \end{array}\)

對稱:\(p4 = \begin{array}{l} \left(\begin{array}{l} 1&2&3\\ 1&3&2 \end{array}\right) \end{array}\)\(p5 = \begin{array}{l} \left(\begin{array}{l} 1&2&3\\ 3&2&1 \end{array}\right) \end{array}\)\(p6 = \begin{array}{l} \left(\begin{array}{l} 1&2&3\\ 2&1&3 \end{array}\right) \end{array}\)

正四邊形

旋轉0°:\(p1 = \begin{array}{l} \left(\begin{array}{l} 1&2&3 &4\\ 1&2&3&4 \end{array}\right) \end{array}\)

旋轉90°:\(p2 = \begin{array}{l} \left(\begin{array}{l} 1&2&3&4\\ 4&1&2&3 \end{array}\right) \end{array}\)

旋轉180°:\(p3 = \begin{array}{l} \left(\begin{array}{l} 1&2&3&4\\ 3&4&1&2 \end{array}\right) \end{array}\)

旋轉270°:\(p4 = \begin{array}{l} \left(\begin{array}{l} 1&2&3&4\\ 2&3&4&1 \end{array}\right) \end{array}\)

對稱:\(p5 = \begin{array}{l} \left(\begin{array}{l} 1&2&3&4\\ 1&4&3&2 \end{array}\right) \end{array}\)\(p6 = \begin{array}{l} \left(\begin{array}{l} 1&2&3&4\\ 3&2&1&4 \end{array}\right) \end{array}\)\(p7 = \begin{array}{l} \left(\begin{array}{l} 1&2&3&4\\ 2&1&4&3 \end{array}\right) \end{array}\)\(p8 = \begin{array}{l} \left(\begin{array}{l} 1&2&3&4\\ 4&3&2&1 \end{array}\right) \end{array}\)

旋轉0°:\((1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)(12)(13)(14)(15)(16)\)

旋轉90°:\((1)(2\ 3\ 4\ 5)(6\ 7)(8\ 9\ 10\ 11)(12\ 13\ 14\ 15)(16)\)

旋轉180°:\((1)(2\ 4)(3\ 5)(6)(7)(8\ 10)(9\ 11)(12\ 14)(13\ 15)(16)\)

旋轉270°:\((1)(2\ 3\ 4\ 5)(6\ 7)(8\ 9\ 10\ 11)(12\ 13\ 14\ 15)(16)\)

\(l = \frac{16 + 2 + 4 + 2}{4} =\)

Bunruside引理

等價類

k階不動置換類

\(G\)\(1,2,\dots ,n\)的置換群,\(k\)\(1\dots n\)中的某個元素,\(G\)中使\(k\)保持不變的置換的全體,極為\(Z_k\)

Polya置換

\(N = {1,2,\dots, n}\)是被著色物體的集合,\(G = {\sigma_1,\sigma_2,\dots,\sigma_g}\)\(N\)上的置換群,用\(m\)種顏色對\(N\)中的元素進行著色,則在\(G\)的作用下不同的著色方案數是

\[M = \frac{1}{|G|}\sum_{i = 1}^{|G|}m^{c(\sigma_i)} \]

其中\(G = {\sigma_1,\sigma_2,\dots,\sigma_k}\)\(c(\sigma_i)\)為置換\(\sigma_i\)的迴圈節數,即輪換個數,\(|G|\)表示置換種數

關鍵在於找到每個置換的迴圈節即可

對於這個置換

迴圈節是(1,3)(2,5)(4),所以迴圈節長度是3

利用polya定理

  1. 寫出置換群
  2. 求出每個置換的輪換個數
  3. 帶入公式求

寫出有置換群

\[\begin{array}{l} \left(\begin{array}{l} 123456 \\ 123456 \end{array}\right)\left(\begin{array}{l} 123456 \\ 612345 \end{array}\right)\left(\begin{array}{l} 123456 \\ 561234 \end{array}\right) \\ \left(\begin{array}{l} 123456 \\ 456123 \end{array}\right)\left(\begin{array}{l} 123456 \\ 345612 \end{array}\right)\left(\begin{array}{l} 123456 \\ 234561 \end{array}\right) \end{array} \]

求出每個置換的輪換個數

\(c_1 = (1)(2)(3)(4)(5)(6)=6, \ c_2 = (1,2,3,4,5,6) = 1,c_3 = (1,3,5)(2,4,6) = 2,\\ c_4 = (1,4)(2,5)(3,6) = 3,c_5 = (1,3,5)(2,4,6) = 2,c_6 = (1,2,3,4,5) = 1\)

帶入公式,用2種顏色去染色

\(M= \frac{2^6+2^1+2^2+2^3+2^2+2^1}{6} = 14\)

常見置換的輪換個數

旋轉

n個點順時針(或逆時針)旋轉i個位置的置換,輪換個數是\(gcd(n,i)\)

假設旋轉i個單位,使得與原來重合,設執行k次,那麼一定滿足\(i * k \mod n == 0\),那麼解得最小\(k = \frac{lcm(i, n)}{i} = \frac{n}{gcd(n, i)}\),所以\(\frac{n}{k} = gcd(n,i)\)

翻轉

n為偶數且對稱軸不過頂點,輪換個數為\(\frac{n}{2}\)

n為偶數且對稱軸過頂點,輪換個數為\(\frac{n}{2} + 1\)

n為奇數,輪換個數為\(\frac{n + 1}{2}\)

模板

對於翻轉,如果n為奇數,找個對稱軸經過點,一共有n條對稱軸,每條對稱軸上有一個點,對稱軸上的珠子構成了一個迴圈,其他\(n-1\)個珠子分別與對稱軸對此構造成\(\frac{n - 1}{2}\)個迴圈,所以迴圈節個數是\(\frac{n - 1}{2} + 1 = \frac{n + 1}{2}\)

如果n是偶數,對稱軸上有兩個點,一個有\(\frac{n}{2}\)條,對稱軸上的兩個點構成兩個迴圈,其他\(n - 2\)個點分別以對稱軸對此構成\(\frac{n - 2}{2}\)個迴圈。還有一種情況,對此軸穿過兩個點之間,這時其他點兩兩對稱,構成\(\frac{n}{2}\)個對稱

對稱有n個置換,旋轉有n個置換,總共2n個置換

時間複雜度\(O(nlogn)\)

#include <iostream>
#include <cstdio>
#define ll long long
int gcd(int a, int b){
    return b == 0 ? a : gcd(b, a % b);
}
ll pow(ll a, ll b){
    ll ans = 1;
    while(b){
        if(b & 1) ans = ans * a;
        a = a * a;
        b >>= 1;
    }
    return ans;
}
int main(){
    int n, m;
    while(~scanf("%d%d", &m, &n)){
        if(n == 0 && m == 0)break;
        ll ans = 0;
        for(int i = 1; i <= n; i++){
            ans += pow(m, gcd(i, n));
        }
        if(n & 1){
            ans += pow(m, n / 2 + 1) * n;
        }else{
            ans += pow(m, n / 2 + 1) * (n / 2);
            ans += pow(m, n / 2) * (n / 2);
        }
        printf("%lld\n", ans / (2 * n));
    }
    return 0;
}

在旋轉部分進行優化,\(\sum_{i = 1}^n n^{gcd(i,n)}\)

\(\sum_{d|n}n^d\times\sum_{k = 1}^{\frac{n}{d}}[gcd(k,\frac{n}{d}) == 1]\)

\(\sum_{d|n}n^d\varphi(\frac{n}{d})\)

時間複雜度\(O(n^{\frac{3}{4}})\)

#include <iostream>
#include <cstdio>
#include <cmath>
#define ll long long
using namespace std ;
const int mod = 1e9 + 7 ; 
ll pow(ll a, ll b, ll p){
    ll ans = 1; a %= p;
    while(b){
        if(b & 1) ans = ans * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return ans;
}
ll phi(ll n) {
    ll ans = n; 
    for(int i = 2; i * i <= n; ++ i ) {
        if(n % i == 0){
            ans -= ans / i;
            while(n % i == 0) n /= i;
        }
    }
    if(n > 1) ans -= ans / n ;
    return ans ; 
}
int main(){
    int T, n, cnt;
    scanf("%d", &T); 
    while( T-- ) {
        scanf("%d", &n);
        ll ans = 0; 
        for(int i = 1; i * i <= n; i++) {
            if(n % i) continue;
            ll p1 = phi(i), f1 = pow(n, n / i, mod); 
            f1 = f1 * p1 % mod; ans = (ans + f1) % mod;
            if(i * i != n) {
                ll p2 = phi(n / i), f2 = pow(n, i, mod) ;
                f2 = f2 * p2 % mod; ans = (ans + f2) % mod;
            }
        }
        printf("%lld\n", ans * pow(n, mod - 2, mod) % mod); 
    }
    return 0 ;
}