Burnside引理与Polya定理 学习笔记
原文链接www.cnblogs.com/zhouzhendong/p/Burnside-Polya.html
问题模型
有一个长度为 $n$ 的序列,序列中的每一个元素有 $m$ 种取值。
如果两个序列循环同构,那么我们称这两个序列等价。
求两两不等价的序列个数。
Burnside引理
假设有若干个置换 $P_1,P_2,\cdots$ ,设由这些置换生成的置换群为 $Q$ 。如果序列 A 可以通过一个 $Q$ 中的置换变成序列 B,那么我们认为 A 和 B 等价。
对于一个置换 $P$ ,如果序列 A 经过置换 $P$ 之后不变,那么我们称序列 A 为置换 $P$ 的一个“不动点”。令 $C(P)$ 表示置换 $P$ 的不动点数。
Burnside引理:
对于一个置换群 $Q$,两两不同的序列个数为
$$\frac 1 {|Q|} \sum_{P\in Q} C(P)$$
Polya定理
Polya定理是Burnside引理的一个具体化。
Polya定理:
假设置换 $P$ 由 $k$ 个轮换组成,那么
$C(P) = m^{k}$
至此,我们已经可以解决最开始的问题模型了。
$$ans = \frac 1n \sum_{i=0}^{n-1} m ^ {\gcd(i,n)}$$
例题 - POJ2409 Let it Bead
题意
有一种项链有 $n$ 个珠子,珠子有 $m$ 种。项链是环,但是没有起始点,也没有方向。也就是说,如果两个项链循环同构或者对称翻转后循环同构,那么他们等价。
求不等价的项链种数。
$n\cdot m \leq 32$ 。
题解
这类问题,我们首先考虑一下置换群 $Q$ 中有哪些元素。
1. 旋转。可以旋转 $0\cdots n-1$ 次,故有 $n$ 种方案。这部分等价于本文开头的问题模型。
2. 翻转。由于任何形如 “旋转 + 翻转 + 旋转” 的操作都可以由一次翻转得到,所以本质上只有翻转操作。不管 $n$ 是奇数还是偶数,都有 $n$ 种本质不同的翻转操作,而且这些操作与之前的旋转也不同。
所以,置换群 $Q$ 中共有 $2n$ 种置换。
现在我们考虑求 $\sum C(P)$ 。
对于 1. 旋转,之前已经提到,这种情况对答案的贡献就是
$$\sum_{i=0}^{n-1} m ^ {\gcd(i,n)}$$
对于 2. 翻转,我们分 $n$ 的奇偶性进行讨论:
n 为奇数:只能将一个顶点与其对边中点所在直线作为对称轴进行翻转:一共有 $n$ 种方案,每种方案都由 $\frac {n+1} 2$ 个轮换构成,故对答案的贡献是
$$n \cdot m ^ {\frac {n+1} 2}$$
n 为偶数:有两种情况:
1. 以两个顶点所在直线为对称轴进行翻转:一共有 $\frac n 2$ 种方案,每种方案都由 $\frac{n+2} 2$ 个轮换构成,故对答案的贡献是
$$\frac n2 \cdot m ^ {\frac {n+2} 2} $$
2. 以两条边的中点所在直线为对称轴进行翻转:一共有 $\frac n 2$ 种方案,每种方案都由 $\frac{n} 2$ 个轮换构成,故对答案的贡献是
$$\frac n2 \cdot m ^ {\frac {n} 2} $$
至此,问题解决。
代码
#include <algorithm> #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> using namespace std; typedef long long LL; int n,m; LL Pow(LL x,LL y){ LL ans=1; for (;y;y>>=1,x*=x) if (y&1) ans*=x; return ans; } int gcd(int a,int b){ return b?gcd(b,a%b):a; } int main(){ while (1){ cin>>m>>n; if (!n&&!m) break; LL ans=0; for (int i=0;i<n;i++) ans+=Pow(m,gcd(n,i)); if (n&1) ans+=Pow(m,(n+1)>>1)*n; else { ans+=Pow(m,n>>1)*(n>>1); ans+=Pow(m,(n+2)>>1)*(n>>1); } ans/=n<<1; cout<<ans<<endl; } return 0; }