burnside引理&polya定理

版权声明:欢迎转载学习! https://blog.csdn.net/m0_38081836/article/details/83826106

前置:

概念:
在数学中,群 ( G , ) (G, ·) 表示一个拥有满足封闭性、结合律、有单位元、有逆元的二元运算的代数结构,包括阿贝尔群、同态和共轭类。

  1. 即G的任意两个元素在 · 下的运算结果都是该集合的一个元素。( a , b G \forall a, b\in G )
  2. 结合律:   a , b , c G .    ( a b ) c = a ( b c ) \forall\ a, b, c \in G.\ \ (a·b)·c = a·(b·c)
  3. 单位元:   e G .    e a = a = a e \exists\ e \in G.\ \ e · a = a = a · e
  4. 逆元:   a G . b G ,    a b = e = b a \forall\ a \in G. \exists b \in G,\ \ a·b=e=b·a
  5. 如果满足了交换律 a   b = b   a a\ ·b=b\ ·a 那么此群为abel群。

置换群:置换为元素的群。


burnside引理(规定了使用颜色的数目)

  • 不动点:在置换 g g 下本身并没有变化,也是指循环节为1的点。在(1, 2)(3)(4)(5)种不动点为 { 3 , 4 , 5 , 6 } \{3, 4, 5, 6\}

设G={a1,a2,…ag}是目标集[1,n]上的置换群。每个置换都写成不相交循环的乘积。 c ( a k ) c(a_k) 是在置换 a k a_k 的作用下不动点的个数,也就是长度为1的循环的个数。通过上述置换的变换操作后可以相等的元素属于同一个等价类。若G将[1,n]划分成l个等价类,则:

l = 1 G ( k = 1 m c ( a i ) ) l = \frac{1}{|G|}(\sum_{k = 1}^{m}c(a_i))

可以理解为在m种置换下不动点个数的和取平均值

polya定理(规定了颜色的种数)

设G={P1,P2,…,Pg}是n个对象的一个置换群, C ( P k ) C(P_k) 是置换Pk的循环的个数,用m种颜色对n个对象着色,着色方案数为 l l
l = k = 1 g m C ( P k ) l = \sum_{k = 1}^{g}m^{C(P_k)}
注: C ( P k ) C(P_k) 也可以理解为在 P k P_k 置换下轨道的个数。


例题:BZOJ1005
burnside + 三维01背包

a c   c o d e : ac\ code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, b) for(int i = a; i <= b; i++)
#define per(i, a, b) for(int i = a; i >= b; i--)
#define met(a, b) memset(a, b, sizeof(a))
const int maxn = 70;
const int inf = 0x3f3f3f3f;
 
int a[maxn][maxn], f[maxn][maxn][maxn], d[maxn], s1, s2, s3, m, mod, n;
bool b[maxn];
 
int dp(int x) {
    int sum = 0;
    met(b, false);
    rep(i, 1, n) {
        if(!b[i]) {
            d[++sum] = 1;
            int p = i;
            b[i] = true;
            while(!b[a[x][p]]) {
                b[a[x][p]] = 1;
                d[sum]++;
                p = a[x][p];
            }
        }
    }
    met(f, 0); f[0][0][0] = 1;
    rep(h, 1, sum) {
        per(i, s1, 0) per(j, s2, 0) per(k, s3, 0) {
            if(i >= d[h]) f[i][j][k] = (f[i][j][k] + f[i - d[h]][j][k]) % mod;
            if(j >= d[h]) f[i][j][k] = (f[i][j][k] + f[i][j - d[h]][k]) % mod;
            if(k >= d[h]) f[i][j][k] = (f[i][j][k] + f[i][j][k - d[h]]) % mod;
        }
    }
    return f[s1][s2][s3];
}
 
int qp(int base, int n) {
    int res = 1;
    while(n) {
        if(n & 1) res = (res * base) % mod;
        base = base * base % mod;
        n >>= 1;
    }
    return res;
}
 
int main() {
    scanf("%d%d%d%d%d", &s1, &s2, &s3, &m, &mod);
    n = s1 + s2 + s3;
    rep(i, 1, m) {
        rep(j, 1, n) {
            scanf("%d", &a[i][j]);
        }
    }
    m++;
    rep(i, 1, n) a[m][i] = i;
    int ans = 0;
    rep(i, 1, m) {
        ans = (ans + dp(i)) % mod;
    }
    ans = ans * qp(m, mod - 2) % mod;
    printf("%d\n", ans);
    return 0;
}


猜你喜欢

转载自blog.csdn.net/m0_38081836/article/details/83826106