Pólya 定理
Polya 定理常在算法竞赛中用于解决计数问题。
首先介绍一下理解此定理需要的数学基础:
1 群
给定集合
G={a,b,c,…}
和集合
G
上的二元运算
2 置换群
置换:集合
{1,2,,…,n}
的一一映射成为一个一元置换,记为:
置换乘积:令 Sn 是 {1,2,…,n} 的置换全体, σ1,σ2 是 Sn 的两个元素,定义它们的乘积为
Sn 对于置换乘法 ∗ 构成群,称为
例:
对于置换群
S3={(112233),(112332),(122133),(122331),(132132),(132231)}按照置换乘法的定义,有:
(122133)(132132)=(122133)(211332)=(112332)
上例中的置换表示方法虽然可用,但有两个显而易见的缺点,所以我们在这里引入另一种表示置换的方法:循环表示法
循环:
置换
(a1a2a2a3……am−1amama1)
称为
m
阶**循环**,简记为
将置换表示为若干循环乘积的方法:
(参考置换定义图)首先在这个置换的第一行任取一个元素,比如说 a1 ,然后去 a1 下面的元素 σ(a1) ,接着取第一行 σ(a1) 下面的元素,以此类推,知道渠道第一行某一元素下面的元素为 a1 时为止。如果这次是索取的元素个数小于 n 则从置换的第一行中去一个以前没有去过的元素重复以上操作,直到取遍第一行的所有元素为止。
-
例:
置换(122331465465) 可以写为 (123)(456)
- 二阶循环
(ab)
叫做
a
和
b 的对换 - 如果两个循环中没有公共元素,则称这两个循环是不相交的。
我们有如下定理:任何一个置换都可以表示称若干个互不相交的循环的乘积,且表示方法是唯一的。
3 Burnside 引理
在计数问题中,常常有给出一些置换,求本质不同的方案数的类型,Burnside 引理解释用于解决此类问题的。
设
G={g1,g2,…,gt}
是
Sn
的子群,若
k∈[1,n],k∈Z
,
G
中使
例:
已知S3={(112233),(112332),(122133),(122331),(132132),(132231)}={e,(23),(12),(123),(132),(13)}
将 S3 中的元素依次记为 g1,g2,g3,g4,g5,g6 ,则Z1={e,(23)},Z2={e,(13)},Z3={e,(12)}且λ1(g1)=3,λ1(g2)=λ1(g3)=λ1(g6)=1,λ1(g4)=λ1(g5)=0
Burnside 引理:
若
G⊆Sn,g∈G
,设
λ(g)
为置换
g
中不变元的个数,则群
Burnside 引理的简单应用
3.1 [BZOJ1004]Cards[HNOI2008]
小春现在很清闲,面对书桌上的 N 张牌,他决定给每张染色,目前小春只有 3 种颜色:红色,蓝色,绿色。他询问 Sun 有多少种染色方案, Sun 很快就给出了答案。进一步,小春要求染出 Sr 张红色,Sb张蓝色,Sg张绝色。他又询问有多少种方案,Sun想了一下,又给出了正确答案。最后小春发明了 M 种不同的洗牌法,这里他又问Sun有多少种不同的染色方案。
两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次)洗成另一种。 Sun 发现这个问题有点难度,决定交给你,答案可能很大,只要求出答案除以 P 的余数( P 为质数)。
100% 数据满足 Max{Sr,Sb,Sg}≤20 。
本题就是 Burnside 引理的简单应用,利用 Burnside 引理,我们可以将问题转换为求每个洗牌方案(即置换)中的不变元个数,这里由于每个颜色个数有限制,所以可以用三维费用背包求。最后在输出答案的时候由于涉及到模意义下的除法可以用拓展欧几里得求逆元输出。
/**************************************************************
Problem: 1004
User: zhangche0526
Language: C++
Result: Accepted
Time:148 ms
Memory:2652 kb
****************************************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
typedef long long ll;
using namespace std;
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
int s1,s2,s3,n,m,P,ans;
int a[70][70],f[70][70][70],d[70];
bool b[70];
int dp(int x)
{
for(int i=1;i<=n;i++)b[i]=0;
int sum=0,p;
for(int i=1;i<=n;i++)
if(!b[i])
{
d[++sum]=1;p=i;
b[p]=1;
while(!b[a[x][p]])
{
d[sum]++;
b[a[x][p]]=1;
p=a[x][p];
}
}
for(int i=s1;i>=0;i--)
for(int j=s2;j>=0;j--)
for(int k=s3;k>=0;k--)
f[i][j][k]=0;
f[0][0][0]=1;
for(int h=1;h<=sum;h++)
for(int i=s1;i>=0;i--)
for(int j=s2;j>=0;j--)
for(int k=s3;k>=0;k--)
{
if(i>=d[h])f[i][j][k]=(f[i][j][k]+f[i-d[h]][j][k])%P;
if(j>=d[h])f[i][j][k]=(f[i][j][k]+f[i][j-d[h]][k])%P;
if(k>=d[h])f[i][j][k]=(f[i][j][k]+f[i][j][k-d[h]])%P;
}
return f[s1][s2][s3];
}
void exgcd(int a,int b,int &x,int &y)
{
if(b==0){x=1;y=0;return;}
exgcd(b,a%b,x,y);
int t=x;x=y;y=t-a/b*y;
}
int main()
{
s1=read(),s2=read(),s3=read(),m=read(),P=read();
n=s1+s2+s3;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
a[i][j]=read();
m++;
for(int i=1;i<=n;i++)a[m][i]=i;
for(int i=1;i<=m;i++)
ans=(ans+dp(i))%P;
int x,y;
exgcd(m,P,x,y);
while(x<=0)x+=P,y-=m;
printf("%d",ans*x%P);
return 0;
}
4 Pólya 定理
在上文提到过,任何一个置换都可以表示成若干个互不相交的循环的成积,且表示的方法是唯一的。
在一个置换
g∈G
中,用
λi(g)
表示长度为
i
的循环的个数,用
设
G={g1,g2,…,gn}
是
n
个对象组成的置换群,用 m 种颜色给这 n 个对象染色,则不同的染色方案数为
又
故还可以写成
参考文献
[1] 林厚从. 信息学竞赛之数学一本通[M]. 南京:东南大学出版社, 2016. 64-90
[2] 吴文虎, 孙贺. 程序设计中的组合数学[M]. 北京:清华大学出版社, 2005. 130-144
[3] wzq_QwQ. BZOJ 1004 [HNOI2008]Cards 置换+burnside定理+逆元[EB/OL]. http://blog.youkuaiyun.com/wzq_QwQ/article/details/47041031, 2015-07-24