Polya 定理入门[Burnside引理,Polya定理,欧拉函数]

Posted zbr162

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Polya 定理入门[Burnside引理,Polya定理,欧拉函数]相关的知识,希望对你有一定的参考价值。

\(这篇blog重点讨论Polya的应用, 更详细的证明请百度 .\)


\(Burnside引理\)

\[L=\frac1|G|\sum_i=1^|G|D(a_i)\]

\(L\): 本质不同的方案数.
\(G\): 置换群集合.
\(a_i\): 置换群中的第 \(i\) 个置换.
\(D(a_i)\): 进行 \(a_i\) 这个置换, 状态不会变化的方案 数量.

该引理与下方内容没有太大关系, 可以暂时忽略.


\(Problem\) 链接
\(N\) 个石子围成一圈, 使用 \(M\) 种颜色染色, 求有多少种本质不同的方案.

借此问题引入 \(Polya定理\) \(↓\)


\(Polya定理\)

\[L=\frac1|G|\sum_i=1^|G|M^C(g_i)\]

先丢出公式.

这道题的 置换群 \(G\): 转\(0\)次, 转\(1\)次 ...转 \(N-1\) 次, (皆为顺时针转动).
若满足旋转 \(k\) 个位置, 状态和原来相同, 那么 \(i\) 位置颜色 等于 \((i+k)\%N\) 位置颜色,
旋转 \(t\) 次, 仍和原来位置相同, 即 \(i\) 位置与 \((i+t*k)\%N\) 位置颜色相同,
\(i\) 旋转 \(t\)\(k\) 次, 一定能回到原来位置, 即可以无限旋转,
所以 \(i\) 就与 所有 \((i+t*k)\%N\) 位置呈现一个封闭的 \(\colorred循环节\).
设转了 \(t\) 次后, 第一次回到 \(i\) 位置, 则
\(t * k=lcm(k, N)=\frack*Ngcd(k,N)\),
\(\therefore t=\fracNgcd(k,N)\),

\(t\)\(\colorred循环节\)长度, 则\(\colorred循环节\)数量为 \(\fracNt=gcd(k,N)\).

公式中 颜色的数量为 \(M\); 在 \(g_i\) 置换下, 有 \(C(g_i)\)\(\colorred循环节\).

此题中 \(C(g_i)=gcd(k,N)\), \[\therefore Ans=L=\frac1N\sum_k=0^N-1M^gcd(k,N)\]


\(拓展 1\)

假如上题增加 \(\colorred对称同构\), 则意味着 原先的两个不同方案 对称 时计为一个方案,
\(N\) 的奇偶 分类讨论:

  1. \(N\) 为奇数, 对称轴上有一个点, 循环节个数为 \(\fracN+12\), 总共有 \(N\) 个对称轴置换, 则对答案贡献为 \(\fracN*M^\fracN+122N\)
    最后的答案为 \[Ans=L=\frac12N(\sum_k=0^N-1M^gcd(k,N)+N*M^\fracN+12)\]
  2. \(N\) 为偶数, 对称轴上可以没有点, 也可以有两个点, 两种对称轴都有 \(\fracN2\) 种, 总共有 \(N\) 个对称轴置换,
    对称轴上无点时, 循环节个数为\(\fracN2\), 对答案贡献为 \(\fracM^\fracN22N\),总贡献为\(\frac\fracN2*M^\fracN22N\).
    对称轴上有点时, 循环节个数为\(\fracN2+1\), 对答案贡献为 \(\fracM^\fracN2+12N\), 总贡献为 \(\frac\fracN2*M^\fracN2+12N\).

    所以最后的答案为
    \[Ans=L=\frac12N(\sum_k=0^N-1M^gcd(k,N)+\fracN2*M^\fracN2+\fracN2*M^\fracN2+1)\]


\(拓展2\)

\(\colorredN<=10^9\) , \(O(N)\)计算下式会 \(TLE\), 需要更快的办法,
\[Ans=L=\frac1N\sum_k=0^N-1M^gcd(k,N)\]

由于 \(gcd(k,N)|N\), 而\(N\)的约数不会超过 \(2\sqrtN\) 个,
考虑枚举 \(d\), \((d|N)\)
则就只需统计 \(gcd(k,N)=d\)\(k\) 的个数.
\(d=gcd(k,N)=gcd(d*t, d*\fracNd)\)
\(t\)\(\fracNd\) 互质, 即 \(\colorredgcd(t, \fracNd) = 1\).
\(\therefore \colorred\varphi(\fracNd)\) 即为 \(gcd(k,N)=d\)\(k\) 的个数.

于是 \[Ans=L=\frac1N\sum_d|N\varphi(\fracNd) *M^d\]
.

\(如何求解 \varphi(x)?\)
根据定义: \[\varphi(x)=x\prod_p_i|x(1-\frac1p_i)\]
通分得: \(\varphi(x) = x\prod_p_i|x\fracp_i-1p_i\)
按上式实现, 时间复杂度小于 \(O(\sqrtN)\), 均摊 \(O(logN)?\)
这里给出求解函数,

int Get_phi(int x)
    int s = x;
    for(int i = 2; i*i <= x; i ++)
        if(x % i == 0) //找到一个质因数
            s = s/i*(i-1);
            while(x%i == 0) x /= i;
        
    if(x > 1) s = s/x*(x-1);    //不可能出现两个大于 sqrt(N) 的质因数, 所以只可能剩下一个, 处理掉就好 .
    return s;

所以 \(O(\sqrtN),O(logN)\) 分别求出所有约数 \(d\)\(\varphi(\fracNd)\) 即可, 时间复杂度 \(O(\sqrtNlogN)\).


\(\mathcalCode\)

#include<bits/stdc++.h>
#define reg register

const int mod = 1e9 + 7;

int T;
int N;

int phi(int x)
        int s = x;
        for(reg int i = 2; i*i <= x; i ++)
                if(x % i == 0)
                        s = s/i * (i-1);
                        while(x % i == 0) x /= i;
                
        if(x > 1) s = s/x * (x-1);
        return s;


int KSM(int a, int b)
        int s = 1; a %= mod;
        while(b)
                if(b & 1) s = 1ll*s*a % mod;
                a = 1ll*a*a % mod, b >>= 1;
        
        return s;


void Work()
        scanf("%d", &N);
        int Ans = 0;
        int lim = sqrt(N);
        for(reg int d = 1; d <= lim; d ++)
                if(N % d) continue ;
                Ans = ( 1ll*Ans + (1ll*phi(N/d) * KSM(N, d) % mod) ) % mod;
                int d_2 = N / d;
                if(d_2 == d) continue ;
                Ans = ( 1ll*Ans + (1ll*phi(N/d_2) * KSM(N, d_2) % mod) ) % mod;
        
        printf("%d\n", (1ll*Ans*KSM(N, mod-2)) % mod);


int main()
        scanf("%d", &T);
        while(T --) Work();
        return 0;

\(例题\)

更多例题请戳 这里 .

以上是关于Polya 定理入门[Burnside引理,Polya定理,欧拉函数]的主要内容,如果未能解决你的问题,请参考以下文章

置换群和Burnside引理,Polya定理

burnside引理&polya定理

Polya定理与Burnside引理

置换群,Polya引理和burnside引理(等价类计数问题)

Burnside引理与Polya定理

积累Burnside引理和Polya定理