版权声明:欢迎转载学习! https://blog.csdn.net/m0_38081836/article/details/83826106
前置:
群
概念:
在数学中,群
表示一个拥有满足封闭性、结合律、有单位元、有逆元的二元运算的代数结构,包括阿贝尔群、同态和共轭类。
- 即G的任意两个元素在 下的运算结果都是该集合的一个元素。( )
- 结合律:
- 单位元:
- 逆元:
- 如果满足了交换律 那么此群为abel群。
置换群: 以置换为元素的群。
burnside引理(规定了使用颜色的数目)
- 不动点:在置换 下本身并没有变化,也是指循环节为1的点。在(1, 2)(3)(4)(5)种不动点为
设G={a1,a2,…ag}是目标集[1,n]上的置换群。每个置换都写成不相交循环的乘积。 是在置换 的作用下不动点的个数,也就是长度为1的循环的个数。通过上述置换的变换操作后可以相等的元素属于同一个等价类。若G将[1,n]划分成l个等价类,则:
可以理解为在m种置换下不动点个数的和取平均值
polya定理(规定了颜色的种数)
设G={P1,P2,…,Pg}是n个对象的一个置换群,
是置换Pk的循环的个数,用m种颜色对n个对象着色,着色方案数为
注:
也可以理解为在
置换下轨道的个数。
例题:BZOJ1005
burnside + 三维01背包
#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;
}