「学习笔记」Burnside 引理 & Polya 定理

前置知识

群,置换,循环,轨道,不动点。

\(G\) 为有限群,\(X\) 为一个集合,\(x \in X\),定义 \(x\) 的轨道为

\[G_x = \{ gx | g \in G \} \]

定义 \(X\) 的轨道数 \(L = |\{ G_x | x \in X \}|\)\(X^g = \{x | x \in X, gx = x \}\) 表示集合 \(X\) 中的所有不动点。

所以,通俗地来说,轨道数就是本质不同的 xxx 的数量。

定理

Burnside 引理:

\[L = \frac 1 {|G|} \sum_{g \in G} |X^g| \]

自己举几个例子玩一玩就可以看出真谛了(

例子

洛谷P4980 【模板】Pólya 定理

这里 \(G\) 中的元素都表示一个旋转了多少的置换。

而如果旋转了 \(i\) 格,那么有 \(\gcd(n, i)\) 个循环,要是不动点则必须满足循环上每个点颜色相同,所以不动点数目就是 \(n^{\gcd(n, i)}\)

所以,答案就是:

\[\frac 1n\sum_{i=1}^n n^{\gcd(n, i)} \]

洛谷P4708 画画

将无标号转成有标号,那么 \(G\) 就是点置换,这样 \(L\) 就表示本质不同的每个点度数都是偶数的图的个数。

可以发现,如果我们要求不动点数目,那么只和每个置换的循环长度可重集有关,那么可以列出式子:

\[\begin{aligned} \mathrm{ans} &= \frac 1 {n!} \sum_{l_1 \leq l_2 \leq \cdots \leq l_k, c} \left[\left(\sum l_i = n\right) \and \left(c_i = \sum [l_j = i] \right)\right] \binom{n}{l_1, l_2, \cdots, l_k} \frac {\prod (l_i - 1)!}{\prod c_i!} F(l_1, l_2, \cdots, l_k)\\ &= \sum_{l_1 \leq l_2 \leq \cdots \leq l_k, c} \left[\left(\sum l_i = n\right) \and \left(c_i = \sum [l_j = i] \right)\right] \frac 1{\prod l_i \prod c_i!} F(l_1, l_2, \cdots, l_k) \end{aligned} \]

现在考虑求 \(F\)

1. 循环内部连边

对于一个循环 \((a_0a_1\cdots a_{k - 1})\),若 \(a_i\)\(a_j\) 有一条边,那么 \(a_{i + 1 \bmod k}\)\(a_{j + 1 \bmod k}\) 之间也一定要连边。

\(k\) 为奇数时,\(\lfloor \frac k2 \rfloor\) 种合法的连边方案都不会改变任意点度数的奇偶性。

\(k\) 为偶数时,仅有 \(a_0\)\(a_{k / 2}\) 连边会导致所有点度数奇偶性发生改变,还有 \(k / 2 - 1\) 种方案没有影响,可以直接加入答案中。

2. 循环间连边

对于任意两个循环 \((a_0a_1\cdots a_{i-1})\)\((b_0b_1\cdots b_{j - 1})\),若 \(a_x\)\(b_y\) 有一条边,那么 \(a_{x + 1 \bmod k}\)\(b_{y + 1 \bmod k}\) 也一定要有连边。

所以说,两个循环中有 \(\gcd(i, j)\) 种连边方式,同时每种方式给每个点带来的度数变化是一样的。

由于一种方式会产生 \(\operatorname{lcm}(i,j )\) 条边,所以每个点 \(a_x\) 就会连出 \(\frac {j} {\gcd(i, j)}\) 条边,\(b_y\) 同理。

如果这条边只改变了 \(a, b\) 中一个循环的度数奇偶性,那么就可以当成一个点对自己的作用;如果同时改变了,记录下来;否则可以直接乘到答案中去。


可以发现循环中每个点度数的奇偶性在任意时刻都相同,那么将一个循环看成一个点。

此时问题转化为:给定 \(k\) 个点和 \(e\) 条边,每个点有 \(p_i\) 次机会使自己的点权异或 \(1\),对于每条边都有机会使边上两个端点的权值异或 \(1\),问操作完之后每个点权值不变的方案数。

假设图连通(如果不连通就直接分开做),考虑每条边都不会改变 \(k\) 个点权值和的奇偶性,所以每个点的操作次数之和必须为偶数,所以操作点的方案数就是 \(2 ^ {\max(\sum p_i - 1, 0)}\)

接下来考虑原图的一棵生成树,可以发现只要非树边的方案确定,树边的方案可以唯一确定,所以这一部分的方案数就是 \(2 ^ {e - k + 1}\)

总方案数就是 \(2 ^ {\max(\sum p_i - 1, 0) + e - k + 1}\)

#include <cstdio>

const int N(55), Mod(998244353);
inline int upd(const int &x) { return x + (x >> 31 & Mod); }
int fastpow(int x, int y)
{
	int ans = 1;
	for (; y; y >>= 1, x = 1ll * x * x % Mod)
		if (y & 1) ans = 1ll * ans * x % Mod;
	return ans;
}

int n, m, a[N], c[N], fac[N], inv[N], g[N][N], fa[N], p[N], ans;
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

void calc()
{
	int res = 1, tot = -m;
	for (int i = 1; i <= a[m]; i++) if (c[i]) res = 1ll * res * inv[c[i]] % Mod;
	for (int i = 1; i <= m; i++) res = 1ll * res * inv[a[i]] % Mod * fac[a[i] - 1] % Mod;
	for (int i = 1; i <= m; i++) fa[i] = i, p[i] = 0;
	for (int i = 1; i <= m; tot += (a[i] - 1) >> 1, i++) if (!(a[i] & 1)) ++p[i];
	for (int i = 1; i <= m; i++)
		for (int j = i + 1; j <= m; j++)
		{
			int d = g[a[i]][a[j]], x = (a[j] / d) & 1, y = (a[i] / d) & 1;
			if (!x && !y) tot += d; else if (!y) p[i] += d; else if (!x) p[j] += d;
			else tot += d, fa[find(i)] = find(j);
		}
	for (int i = 1; i <= m; i++) if (i != find(i)) p[find(i)] += p[i];
	for (int i = 1; i <= m; i++) if (find(i) == i) tot += p[i] ? p[i] : 1;
	ans = (ans + 1ll * res * fastpow(2, tot)) % Mod;
}

void dfs(int n, int d)
{
	if (n == 0) return calc();
	for (int i = d; i <= n; i++) ++c[a[++m] = i], dfs(n - i, i), --m, --c[i];
}

int main()
{
	std::scanf("%d", &n), fac[0] = 1;
	for (int i = 1; i <= n; i++) fac[i] = 1ll * fac[i - 1] * i % Mod;
	inv[n] = fastpow(fac[n], Mod - 2);
	for (int i = n; i; i--) inv[i - 1] = 1ll * inv[i] * i % Mod;
	for (int i = 1; i <= n; i++) g[i][0] = g[0][i] = i;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= i; j++) g[i][j] = g[j][i] = g[j][i % j];
	dfs(n, 1), printf("%d\n", ans);
	return 0;
}
posted @ 2021-02-26 17:08  xgzc  阅读(257)  评论(2编辑  收藏  举报