前置:
群
概念:
在数学中,群
(
G
,
⋅
)
(G, ·)
(G,⋅)表示一个拥有满足封闭性、结合律、有单位元、有逆元的二元运算的代数结构,包括阿贝尔群、同态和共轭类。
- 即G的任意两个元素在 ⋅ · ⋅下的运算结果都是该集合的一个元素。( ∀ a , b ∈ G \forall a, b\in G ∀a,b∈G)
- 结合律: ∀ a , b , c ∈ G . ( a ⋅ b ) ⋅ c = a ⋅ ( b ⋅ c ) \forall\ a, b, c \in G.\ \ (a·b)·c = a·(b·c) ∀ a,b,c∈G. (a⋅b)⋅c=a⋅(b⋅c)
- 单位元: ∃ e ∈ G . e ⋅ a = a = a ⋅ e \exists\ e \in G.\ \ e · a = a = a · e ∃ e∈G. e⋅a=a=a⋅e
- 逆元: ∀ a ∈ G . ∃ b ∈ G , a ⋅ b = e = b ⋅ a \forall\ a \in G. \exists b \in G,\ \ a·b=e=b·a ∀ a∈G.∃b∈G, a⋅b=e=b⋅a
- 如果满足了交换律 a ⋅ b = b ⋅ a a\ ·b=b\ ·a a ⋅b=b ⋅a那么此群为abel群。
置换群: 以置换为元素的群。
burnside引理(规定了使用颜色的数目)
- 不动点:在置换 g g g下本身并没有变化,也是指循环节为1的点。在(1, 2)(3)(4)(5)种不动点为 { 3 , 4 , 5 , 6 } \{3, 4, 5, 6\} {3,4,5,6}
设G={a1,a2,…ag}是目标集[1,n]上的置换群。每个置换都写成不相交循环的乘积。 c ( a k ) c(a_k) c(ak)是在置换 a k a_k ak的作用下不动点的个数,也就是长度为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)) l=∣G∣1(k=1∑mc(ai))
可以理解为在m种置换下不动点个数的和取平均值
polya定理(规定了颜色的种数)
设G={P1,P2,…,Pg}是n个对象的一个置换群,
C
(
P
k
)
C(P_k)
C(Pk)是置换Pk的循环的个数,用m种颜色对n个对象着色,着色方案数为
l
l
l
l
=
∑
k
=
1
g
m
C
(
P
k
)
l = \sum_{k = 1}^{g}m^{C(P_k)}
l=k=1∑gmC(Pk)
注:
C
(
P
k
)
C(P_k)
C(Pk)也可以理解为在
P
k
P_k
Pk置换下轨道的个数。
例题:BZOJ1005
burnside + 三维01背包
a c c o d e : ac\ code: 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;
}