「算法笔记」Polya 定理
一、前置概念
接下来的这些定义摘自 置换群 - OI Wiki。
1. 群
若集合 \(s\neq \varnothing\) 和 \(S\) 上的运算 \(\cdot\) 构成的代数结构 \((S,\cdot)\) 满足一下性质:
封闭性:\(\forall a,b\in S,a\cdot b\in S\)。
结合律:\(\forall a,b,c\in S,(a\cdot b)\cdot c=a\cdot (b\cdot c)\)。
单位元:\(\exists e\in S,\forall a\in S,e\cdot a=a\cdot e=a\)。
逆元:\(\forall a\in S,\exists b\in S,a\cdot b=b\cdot a=e\),称 \(b\) 为 \(a\) 的逆元,记为 \(a^{-1}\)。
则称 \((S,\cdot)\) 为一个 群。例如,整数集合整数集的加法 \((\mathbb{Z},+)\) 构成一个群,单位元是 \(0\),一个整数的逆元是它的相反数。
子群:若 \((S,\cdot)\) 是群,\(T\) 是 \(S\) 的非空子集,且 \((T,\cdot)\) 也是群,则称 \((T,\cdot)\) 是 \((S,\cdot)\) 的 子群。
2. 置换
有限集合到自身的双射(即一一对应)称为置换。集合 \(S=\{a_1,a_2,\cdots,a_n\}\) 上的置换可以表示为
\(f=\begin{pmatrix} a_1,a_2,\cdots,a_n \\ a_{p_1},a_{p_2},\cdots,a_{p_n} \end{pmatrix}\)
意为将 \(a_i\) 映射为 \(a_{p_i}\),其中 \(p_1,p_2,\cdots,p_n\) 是 \(1,2,\cdots,n\) 的一个排列。显然 \(S\) 上所有置换的数量为 \(n!\)。
3. 置换的乘法
对于两个置换 \(f=\begin{pmatrix} a_1,a_2,\cdots,a_n \\ a_{p_1},a_{p_2},\cdots,a_{p_n} \end{pmatrix}\) 和 \(g=\begin{pmatrix} a_{p_1},a_{p_2},\cdots,a_{p_n} \\ a_{q_1},a_{q_2},\cdots,a_{q_n} \end{pmatrix}\),\(f\) 和 \(g\) 的乘积记为 \(f\circ g\),其值为 \(f\circ g=\begin{pmatrix}a_1,a_2,\dots,a_n\\ a_{q_1},a_{q_2},\dots,a_{q_n}\end{pmatrix}\)
简单来说就是先后经过 \(f\) 的映射,再经过 \(g\) 的映射。
4. 置换群
可以理解为是将置换作为元素的群。
易证,集合 \(S\) 上的所有置换关于「置换的乘法」满足封闭性(置换的乘积也是置换)、结合律、有单位元(恒等置换,即每个元素映射成它自己)、有逆元(交换置换表示中的上下两行),因此构成一个群。
这个群的任意一个 子群 即成为 置换群。
5. 循环置换
循环置换是一类特殊的置换。记
\(\begin{pmatrix} a_1,a_2,\cdots,a_m\end{pmatrix}=\begin{pmatrix} a_1,a_2,\cdots,a_{m-1},a_m\\a_2,a_3,\cdots,a_m,a_1\end{pmatrix}\)
为 \(m\) 阶循环。若两个循环置换不含有相同的元素,则称它们是 不相交 的。
有如下定理:任意一个置换都可以分解为若干不相交的循环置换的乘积,例如
\(\begin{pmatrix}a_1,a_2,a_3,a_4,a_5\\a_3,a_1,a_2,a_5,a_4\end{pmatrix}=\begin{pmatrix}a_1,a_3,a_2\end{pmatrix}\circ \begin{pmatrix}a_4,a_5\end{pmatrix}\)
置换的 循环节数 是上述表示中循环置换的个数。如上述例子中循环节数为 \(3\)。
如果把元素视为图的节点,映射关系视为有向边,则每个节点的入度和出度都为 \(1\),因此形成的图形必定是若干个环的集合,而一个环即可用一个循环置换表示。
二、Burnside 引理
Update on 2021.6.1
修改了表述,应该会清楚好懂一点。
\(n\) 个珠子的项链做黑白二染色,\(2^n\) 种。
但是项链可以旋转、对称,这些操作下相同的应该视为同一种。\(4\) 种:白白白,黑黑黑,白白黑,黑黑白。
Burnside 定理:
操作:旋转,对称,不变……(\(m\) 种操作)
等价类:可以通过互相转化的状态组成一个等价类。
想求:不同等价类总数。
对每一种操作 \(g\),称在这种操作下不变的状态为 \(g\) 的不动点。
p>则不同等价类总数 \(=\frac{(\sum\limits_{g为m种操作之一}\quad\quad\quad g的不动点个数)}{m}\)。
Update 前
Update 前的表述,可跳过 QAQ。
对于 \(\forall k\in S\),记 \(k\) 所在的 等价类 为 \(E_k\),\(E_k=\{x\mid \exists f\in G,f(k)=x\}\),即 \(k\) 在 \(G\) 的作用下所能变化成的所有元素的集合。(若 \(\exists f\in G,f(x)=y\),则 \(x\) 和 \(y\) 等价,所有互相等价的元素组成一个等价类。其中 \(f(x)\) 表示 \(x\) 进行置换 \(y\) 的结果)
对于 \(\forall k\in S\),记 \(k\) 的 不动置换类 为 \(Z_k\),\(Z_k=\{f\mid f\in G,f(k)=k\}\),即 \(G\) 中使 \(k\) 保持不变的置换的全体。
Burnside 引理:对于 \(\forall f\in G\),记 \(D(f)=\sum\limits_{x\in S}[f(x)=x]\),即 \(S\) 中在置换 \(f\) 下没有改变的元素的个数。设 \(L\) 为等价类个数。则:\(\displaystyle L=\frac{1}{|G|}\sum\limits_{f\in G} D(f)\)。证明。
换一种说法:对于一个置换 \(f\),若一个着色方案 \(s\) 经过置换后不变,则称 \(s\) 为 \(f\) 的不动点。记 \(f\) 的不动点数目为 \(D(f)\),则等价类个数为所有 \(D(f)\) 的平均值。
等价类个数可以理解为 本质不同 的方案数。
正常一点的语言:本质不同的方案数为在每个置换下稳定不动的方案的总和除以总置换数。
三、Pólya 定理
容易发现,在 Burnside 引理中,要计算 \(D(f)\) 的值不是很容易。Pólya 定理 实质上是 Burnside 引理 的一个扩展。
Pólya 定理:设 \(G\) 是 \(p\) 个对象的置换群,用 \(m\) 种颜色涂染 \(p\) 个对象。对于 \(\forall f\in G\),记 \(c(f)\) 为置换 \(f\) 的循环节数,则不同染色方案为:\(\displaystyle L=\frac{1}{|G|}\sum\limits_{f\in G}m^{c(f)}\)。
要得到在置换下稳定不动的方案,即把置换的每个循环节都染上相同的颜色,所以 \(D(f)=m^{c(f)}\)。根据 Burnside 引理 就能得到 Pólya 定理。
它解决的问题有限。通常用 DP 或 组合数 来扩展此类问题。
黄队博客 中的表述(Polya 计数法):设 \(G\) 是 \(p\) 个对象的一个置换群,用 \(m\) 种颜色涂染 \(p\) 个对象,则不同染色方案为:
\(\displaystyle L=\frac{1}{|G|}(m^{c(g_1)}+m^{c(g_2)}+\cdot+m^{c(g_s)})\)
其中 \(G={g_1,\cdots,g_s}\),\(c(g_i)\) 为置换 \(g_i\) 的环数。
四、应用与例题
对于没有接触过概念的读者来说,以上内容第一次读的时候可能会有些生涩,建议多读几遍。如果下面题目忘记写数据范围了那就去看原题吧 QwQ。
1. 常见置换的循环节数
1. 将长度为 \(n\) 的序列或环循环移 \(k\) 位:这个置换的循环节数为 \(\gcd(n,k)\)。具体地,这个置换是由 \(\gcd(n,k)\) 个 \(\frac{n}{\gcd(n,k)}\) 阶循环构成的。(\(\frac{\text{lcm}(n,k)}{k}=\frac{n}{\gcd(n,k)}\))
2. 将长度为 \(n\) 的环沿对称轴反转。易知共有 \(n\) 种翻转置换。
若 \(n\) 为奇数,那么所有的轴会且只会经过一个环上的元素。每一个置换都是由一个 \(1\) 阶循环和 \(\frac{n-1}{2}\) 个 \(2\) 阶循环组成的,即 \(n\) 种翻转的循环节数均为 \(\frac{n+1}{2}\)。
否则,有两种情况:对称轴在两点之间时,对称轴左右两侧的点恰好一一配对,这 \(\frac{n}{2}\) 个轴不经过环上的元素,这些轴对应的翻转置换由 \(\frac{n}{2}\) 个 \(2\) 阶循环组成,即循环节数为 \(\frac{n}{2}\);对称轴恰好穿过两点,这 \(\frac{n}{2}\) 个轴经过环上 \(2\) 个元素,这些轴对应的翻转置换由 \(2\) 个 \(1\) 阶循环和 \(\frac{n-2}{2}\) 个 \(2\) 阶循环组成,即循环节数为 \(\frac{n}{2}+1\)。
2. Luogu P1446 [HNOI2008]Cards
题目大意:有 \(n\) 张牌,染三种颜色,每种颜色规定数目。给出 \(m\) 种不同的洗牌方法。
两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次)洗成另一种。
求方案数对 \(p\) 取模的结果。
Solution:
把洗牌方法看作置换,染色方案看作“元素”。
输入数据保证任意多次洗牌都可用这 \(m\) 种洗牌法中的一种代替,且对每种洗牌法,都存在一种洗牌法使得能回到原状态。所以它满足封闭性,并且存在逆元。我们需要加上 恒等置换(即每个元素映射成它自己),使其存在单位元。由于单位元满足 \(a\cdot e=a\),所以并不会对答案产生影响。此时给出的置换是一个置换群,总置换数为 \(m+1\)。
因为染色存在数目限制,所以不能直接使用 Pólya 定理。
根据 Burnside 引理,本质不同的方案数为在每个置换下稳定不动的方案的总和(不动点数目之和)除以总置换数。
而要得到在置换下稳定不动的方案,那么就要把置换的每个循环节都 染上相同的颜色。
每个置换中都有若干个循环,根据给出的置换可以求出循环节数。考虑用 DP 求出每个循环节都染上相同的颜色,并且每种颜色的总和符合题目要求的方案总数。
所以,对于每一个置换,单独考虑每个循环染哪种颜色,可以通过一个类似 背包 的过程实现(把每一个循环看作一个物品,物品的重量为循环元素个数)。具体地,令 \(f_{i,j,k}\) 表示三种颜色分别用了多少的方案数。
答案为在每个置换下稳定不动的方案的总和除以总置换数。
- #include<bits/stdc++.h>
- #define int long long
- using namespace std;
- const int N=30,M=70;
- int n,R,B,G,m,mod,a[M],sz[M],cnt,f[N][N][N],ans;
- bool vis[M];
- int mul(int x,int n,int mod){ //保证 mod 为质数,可以使用快速幂求逆元
- int ans=mod!=1;
- for(x%=mod;n;n>>=1,x=x*x%mod)
- if(n&1) ans=ans*x%mod;
- return ans;
- }
- int solve(){
- memset(vis,0,sizeof(vis)),cnt=0;
- for(int i=1;i<=n;i++){
- if(vis[i]) continue;
- int x=i,len=0;
- while(!vis[x]) len++,vis[x]=1,x=a[x]; //求循环中的元素个数
- sz[++cnt]=len; //cnt: 循环节数
- }
- memset(f,0,sizeof(f)),f[0][0][0]=1;
- for(int t=1;t<=cnt;t++) //类似背包的过程
- for(int i=R;i>=0;i--)
- for(int j=G;j>=0;j--)
- for(int k=B;k>=0;k--){
- if(i>=sz[t]) (f[i][j][k]+=f[i-sz[t]][j][k])%=mod;
- if(j>=sz[t]) (f[i][j][k]+=f[i][j-sz[t]][k])%=mod;
- if(k>=sz[t]) (f[i][j][k]+=f[i][j][k-sz[t]])%=mod;
- }
- return f[R][G][B];
- }
- signed main(){
- scanf("%lld%lld%lld%lld%lld",&R,&G,&B,&m,&mod),n=R+G+B;
- for(int i=1;i<=m;i++){
- for(int j=1;j<=n;j++) scanf("%lld",&a[j]);
- ans=(ans+solve())%mod;
- }
- for(int i=1;i<=n;i++) a[i]=i; //加上恒等置换(自己到自己)
- ans=(ans+solve())%mod,printf("%lld\n",ans*mul(m+1,mod-2,mod)%mod);
- return 0;
- }
3. Luogu P4980【模板】Pólya 定理
题目大意:给定一个 \(n\) 个点 \(n\) 条边的环,有 \(n\) 种颜色,给每个顶点染色,求本质不同的染色方案数,答案对 \(10^9+7\) 取模。
本质不同指的是不能通过旋转变得与其他染色方案相同。\(t\leq 10^3,n\leq 10^9\)。
Solution:
有 \(n\) 种循环移位,根据前面「常见置换的循环节数」中「将长度为 \(n\) 的环循环移 \(k\) 位:这个置换的循环节数为 \(\gcd(n,k)\)」以及 Pólya 定理 可得:答案为 \(\displaystyle \frac{1}{n}\sum\limits_{k=1}^n n^{\gcd(n,k)}\)。
推一下式子:
枚举 \(\gcd\) 变为:\(\displaystyle \frac{1}{n}\sum\limits_{d\mid n} n^d \times \sum\limits_{k=1}^{\frac{n}{d}}[\gcd(k,\frac{n}{d})=1]\)。
后面那个式子是欧拉函数,直接代入:\(\displaystyle \frac{1}{n}\sum\limits_{d\mid n} n^d \varphi(\frac{n}{d})\)。
所以答案为 \(\displaystyle \frac{1}{n}\sum\limits_{d\mid n} n^d \varphi(\frac{n}{d})\)。
- #include<bits/stdc++.h>
- #define int long long
- using namespace std;
- const int mod=1e9+7;
- int t,n,ans;
- int mul(int x,int n,int mod){
- int ans=mod!=1;
- for(x%=mod;n;n>>=1,x=x*x%mod)
- if(n&1) ans=ans*x%mod;
- return ans;
- }
- int phi(int n){ //求欧拉函数
- int ans=n;
- for(int i=2;i<=sqrt(n);i++){
- if(n%i!=0) continue;
- ans=ans/i*(i-1);
- while(n%i==0) n/=i;
- }
- if(n>1) ans=ans/n*(n-1);
- return ans%mod;
- }
- signed main(){
- scanf("%lld",&t);
- while(t--){
- scanf("%lld",&n),ans=0;
- for(int i=1;i<=sqrt(n);i++){
- if(n%i!=0) continue;
- ans=(ans+mul(n,i,mod)*phi(n/i)%mod)%mod;
- if(i*i!=n) ans=(ans+mul(n,n/i,mod)*phi(i)%mod)%mod; //套式子
- }
- printf("%lld\n",ans*mul(n,mod-2,mod)%mod);
- }
- return 0;
- }
4. UVA10601 Cubes
题目大意:给正方体的 \(12\) 条棱染色,有 \(6\) 种颜色,每种颜色规定数目,求本质不同的方案数(旋转后相同的方案算同一种)。多组数据,\(1\leq t\leq 60\)。
Solution:
一个正方体共有 \(24\) 种旋转。根据这些不同的旋转方法,构造对应的关于边的置换群。
不旋转:\(1\) 种,分解为 \(12\) 个 \(1\) 阶循环。
以一对相对面的中心为轴:
旋转 \(90^{\circ}\):\(6\) 种,分解为 \(3\) 个 \(4\) 阶循环。
旋转 \(180^{\circ}\):\(3\) 种,分解为 \(6\) 个 \(2\) 阶循环。
以一对相对棱的中心为轴:
- 旋转 \(180^{\circ}\):\(6\) 种,分解为 \(2\) 个 \(1\) 阶循环和 \(5\) 个 \(2\) 阶循环。
以一对对顶点为轴:
- 旋转 \(120^{\circ}\):\(8\) 种,分解为 \(4\) 个 \(3\) 阶循环。
因为染色存在数目限制,所以不能直接使用 Pólya 定理。与前面的「Luogu P1446 [HNOI2008]Cards」类似,要把置换的每个循环节都染上相同的颜色。
然后你可以写 组合数 或 六维背包。
五、习题
- Luogu P2561 [AHOI2002]黑白瓷砖(Code)
- SP419 Transposing is Fun
- SP422 Transposing is Even More Fun
- BZOJ 1478 Sgu282 Isomorphism
顺便说说,这篇文章写得挺烂的,还是看 这里 吧 QAQ
六、参考资料
「算法笔记」Polya 定理的更多相关文章
- 「算法笔记」快速数论变换(NTT)
一.简介 前置知识:多项式乘法与 FFT. FFT 涉及大量 double 类型数据操作和 \(\sin,\cos\) 运算,会产生误差.快速数论变换(Number Theoretic Transfo ...
- 「算法笔记」树形 DP
一.树形 DP 基础 又是一篇鸽了好久的文章--以下面这道题为例,介绍一下树形 DP 的一般过程. POJ 2342 Anniversary party 题目大意:有一家公司要举行一个聚会,一共有 \ ...
- 「算法笔记」2-SAT 问题
一.定义 k-SAT(Satisfiability)问题的形式如下: 有 \(n\) 个 01 变量 \(x_1,x_2,\cdots,x_n\),另有 \(m\) 个变量取值需要满足的限制. 每个限 ...
- 「算法笔记」BSGS 与 exBSGS
一.离散对数 给定 \(a,b,m\),存在一个 \(x\),使得 \(\displaystyle a^x\equiv b\pmod m\) 则称 \(x\) 为 \(b\) 在模 \(m\) 意义下 ...
- 「算法笔记」状压 DP
一.关于状压 dp 为了规避不确定性,我们将需要枚举的东西放入状态.当不确定性太多的时候,我们就需要将它们压进较少的维数内. 常见的状态: 天生二进制(开关.选与不选.是否出现--) 爆搜出状态,给它 ...
- 「算法笔记」旋转 Treap
一.引入 随机数据中,BST 一次操作的期望复杂度为 \(\mathcal{O}(\log n)\). 然而,BST 很容易退化,例如在 BST 中一次插入一个有序序列,将会得到一条链,平均每次操作的 ...
- 「算法笔记」FHQ-Treap
右转→https://www.cnblogs.com/mytqwqq/p/15057231.html 下面放个板子 (禁止莱莱白嫖板子) P3369 [模板]普通平衡树 #include<bit ...
- 「算法笔记」Min_25 筛
戳 这里(加了密码).虽然写的可能还算清楚,但还是不公开了吧 QwQ. 真的想看的 私信可能会考虑给密码 qwq.就放个板子: //LOJ 6053 简单的函数 f(p^c)=p xor c #inc ...
- 「算法笔记」快速傅里叶变换(FFT)
一.引入 首先,定义多项式的形式为 \(f(x)=\sum_{i=0}^n a_ix^i\),其中 \(a_i\) 为系数,\(n\) 为次数,这种表示方法称为"系数表示法",一个 ...
随机推荐
- day07 Linux配置修改
day07 Linux配置修改 昨日回顾 1.系统目录 /etc :系统配置目录 /bin-> /usr/bin :保存常用命令的目录 /root :超级管理员目录 /home :普通管理员目录 ...
- 如果通过 IP 判断是否是爬虫
通过 IP 判断爬虫 如果你查看服务器日志,看到密密麻麻的 IP 地址,你一眼可以看出来那些 IP 是爬虫,那些 IP 是正常的爬虫,就像这样: 在这密密麻麻的日志里面,我们不仅要分辨出真正的爬虫 I ...
- 【swift】Xcode未响应(卡死、卡住、CPU满载、忙碌、转圈圈)
在尝试了网上的方法,依然没能解决问题,尝试如下: 1.去自己项目的路径,找到<你的项目名.xcodeproj>,点击[显示包内容],删除xcuserdata文件夹 2.去Library,把 ...
- 机器学习常用python包
(py37) ai@ai:~$ pip freeze |grep -v '@' astor==0.8.1 certifi==2021.5.30 chardet==4.0.0 cycler==0.10. ...
- Xcode中匹配的配置包的存放目录
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport
- tomcat 之 httpd session stiky
# 注释中心主机 [root@nginx ~]# vim /etc/httpd/conf/httpd.conf #DocumentRoot "/var/www/html" #:配置 ...
- 如何在linux 上配置NTP 时间同步?
故障现象: 有些应用场景,对时间同步的要求严格,需要用到NTP同步,如何在linux上配置NTP时间同步? 解决方案: 在linux 上配置NTP 时间同步,具休操作步骤,整理如下: 1.安装软件包( ...
- this指针的用法和基本分析
当在不同的对象中采用this指针,就已经是在给它赋值了.对象各自的this指针指向各自对象的首地址,所以不同对象的this指针一定指向不同的内存地址. this 指针是由系统自动提供的指向对象的特殊指 ...
- 【Spark】【复习】Spark入门考前概念相关题复习
Spark考前概念相关题复习 AUthor:萌狼蓝天 哔哩哔哩:萌狼蓝天 博客园:我的文章 - 萌狼蓝天 博客:萌狼工作室 - 萌狼蓝天 (mllt.cc) 选择题 Hadoop 1.HADOOP的三 ...
- C#和.NET 框架
C#和.NET框架 在.NET之前 20世纪90年代,微软平台多数程序员使用VB.C或C++.他们使用的技术都有问题. 技术 问题 纯Win32 API 不是面向对象,工作量比MFC大 MFC(Mic ...