您的位置:首页 > 其它

polya计数回顾

2015-11-03 13:30 246 查看
burnside引理

设G={g1,g2...gk},k=|G|,是[1,n]上的置换群,令c(gi)表示置换gi下不动点的个数,那么G将[1,n]划分为等价类>的个数是:

l=1|G|∑j=1|G|c(gi)

即是说,等价类个数等于不动点个数的均值。

如果存在gi将gi(a)−>b那么我们就说观测到a和b等价。换句话说,我们看到的a和b是同一个东西。

polya定理

设G={g1,g2...gk},k=|G|,是[1,n]上的置换群,令C(gi)表示置换gi下循环节的个数,现在用m个颜色对[1,n]着色,那么在G作用下,[1,n]的不同着色方案数为:

l=1|G|∑j=1|G|mC(gi)

polya定理是burnside的特例。

需要注意的是,burnside算的是[1,n]这n个数的不同等价类的个数;polya算的是mn个方案数中不同等价类的个数。因此,burnside中的[1,n]是计数对象,而polya中的方案数是计数对象。

burnside中的g直接作用于计数对象[1,n];而polya中的g虽然也作用于[1,n],但[1,n]不是计数对象,方案数才是,但是g通过作用到[1,n]间接作用到方案数上面。两式对比,容易发现mC(gi)是burnside中的不动点数

比如n=4,g=(123)(4),着色方案为f=(abcd),那么g(f)=(cabd)。不动点是自己映射到自己,即g(f)=f。对于上例就是(cabd)=(abcd),于是有c=a,a=b,b=c,d=d。因此如果方案f是g的不动点,那么在g的每个循环节内,f只能染一种颜色。换句话说,用f染完色后,g的循环节内的点颜色相同。对于循环节为C(gi)的置换,其不动点个数为mC(gi)

顺便上一题巩固一下

[HNOI2008]Cards

这里不能直接套用polya,因为每种颜色的使用量是有限制的,因此考虑用burnside计算。对于置换g,因为同一循环节里面只能用同一种颜色,因此我们统计出g的第i个循环节里面有ci个数。然后我们用这些数dp就可以了。

dp[i][r][g][b]表示前i个循环节,用r中r色,g中g色,b种b色着色的方案数,那么:dp[i][r][g][b]=dp[i][r−ci][g][b]+dp[i][r][g][b−ci]+dp[i][r][g−ci][b]

/**************************************************************
Problem: 1004
User: 63116021
Language: C++
Result: Accepted
Time:120 ms
Memory:3616 kb
****************************************************************/

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define clr(A) memset(A,0,sizeof(A))
using namespace std;

const int MM = 10000;

int r,b,g,m,p;
int fg = 0;
typedef struct GG{
int x,y;
GG(int _x,int _y){
x = _x,y = _y;
}
}G;

G Ext_gcd(int a,int b)
{
if(b==0) return G(1,0);
G tmp = Ext_gcd(b,a%b);
return G(tmp.y,tmp.x-a/b*tmp.y);
}

int getcir(int a[],int nn)
{
int hash[nn+3];
int B[nn+2];
clr(hash);
int res = 0;
for(int i = 1;i<=nn;i++)
if(!hash[i])
{
B[++res] = 1;
hash[i] = 1;
int tmp = a[i];
while(tmp!=i)
{
hash[tmp] = 1,B[res]++,tmp = a[tmp];
}
}

int F[res+2][b+2][r+2][g+2];
clr(F);
F[0][0][0][0] = 1;
for(int i = 1;i<=res;i++)
for(int sb = 0;sb<=b;sb++)
for(int sr = 0;sr<=r;sr++)
for(int sg = 0;sg<=g;sg++)
//if(sb+sr+sg>=B[i])
{
if(sb>=B[i]) F[i][sb][sr][sg] += F[i-1][sb-B[i]][sr][sg];
if(sr>=B[i]) F[i][sb][sr][sg] += F[i-1][sb][sr-B[i]][sg];
if(sg>=B[i]) F[i][sb][sr][sg] += F[i-1][sb][sr][sg-B[i]];
F[i][sb][sr][sg] %= p;
}
if(res == nn) fg = 1;
return F[res][b][r][g];
}
int main()
{
//freopen("Pr_temp.in","r",stdin);
scanf("%d%d%d%d%d",&r,&b,&g,&m,&p);
int n = r+b+g;
int A[n+2];
int ans = 0;
for(int i = 1;i<=m;i++)
{
for(int j = 1;j<=n;j++)
scanf("%d",A+j);
ans = (ans+getcir(A,n)) % p;
}
if(!fg){
for(int i = 1;i<=n;i++)
A[i] = i;
ans = (ans+getcir(A,n)) % p;
m++;
}
G Gg = Ext_gcd(m,p);
int Inv = (Gg.x+p) % p;
printf("%d\n",Inv*ans%p);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  polya math