Pólya 定理学习笔记 | ABC428G 题解

Pólya 定理学习笔记 | ABC428G 题解

用来对在若干置换下本质不同的方案数计数。


(这里会有一些对引理和定理的证明,但是先咕掉((


首先是 Burnside 引理:

结论是,假设群 \(G\) 作用于集合 \(X\) 上。

\(O_x\) 表示 \(x\in X\) 的轨道,即 \(\{gx|g\in G\}\)

\(X_g\) 表示 \(g\in G\) 的所有不动点,即 \(\{x|x\in X,gx=x\}\)

Burnsize 引理指出:

\[|\{O_x|x\in X\}|=\dfrac 1{|G|}\sum_{g\in G}|X_g| \]


接下来是 Pólya 定理:

假设群 \(G\) 作用于 \(X\) 上,\(Y\) 是一个有限集,令 \(X^Y\) 是全体映射 \(X\rightarrow Y\) 构成的集合。

(可以认为 \(X\) 是元素,\(Y\) 是颜色, \(X^Y\) 表示所有的染色方案。

定义 \(c(g)\) 表示,取与 \(g\) 等价的置换 \(\sigma_g(x)=gx\),那么 \(c(x)\) 等于 \(\sigma_g\) 分解成的不相交轮换数量。

那么著名的 Pólya 定理断言:

\[|\{O_x|x\in X^Y\}|=\dfrac 1{|G|}\sum_{g\in G} |Y|^{c(g)} \]


例题:ABC428G Necklace

权值为 \(v\in[2,n]\) 的珠子有 \(a_v\) 种,每种珠子都有无限个。

对于所有 \(w\in[2,m]\) 求出若干珠子构成的环,权值之积恰好等于 \(w\) 的不同方案数。方案相同当且仅当其仅通过旋转重合。

\[m\le 5\times 10^5 \]


首先不难发现环长至多为 \(\log m\)

\(f_{i,j}\) 表示,长为 \(i\),积为 \(j\)序列 方案数(即不考虑旋转重合)。

有显然转移,

\[f_{i,j} \leftarrow f_{i-1,\frac jv} \times a_v \]

根据 Burnside 引理,有

\[\begin{align*} \text{ans}(w)&=\sum_{k=1}^{\log m}\dfrac 1k\sum_{i=1}^k f_{\gcd(i,k),\sqrt[\frac k{\gcd(i,k)}]{w}} \\&=\sum_{k=1}^{\log m}\dfrac 1k \sum_{d|k} \varphi(\frac kd)f_{d,\sqrt[\frac kd]{w}} \\&=\sum_{k=1}^{\log m}\dfrac 1k \sum_{d|k} \varphi(d)f_{\frac kd,\sqrt[d]{w}} \\&=\sum_{k=1}^{\log m}\sum_{d|k} \dfrac 1k\varphi(d)f_{\frac kd,\sqrt[d]{w}} \\&=\sum_{d=1}^{\log m}\sum_{d|k} \dfrac 1k\varphi(d)f_{\frac kd,\sqrt[d]{w}} \end{align*} \]

注意到当 \(d\ge 2\)\(\sqrt[d]{w}\) 为整数的位置不会很多。

因此复杂度为 \(\mathcal O(m\log m)\)

Code
#include <iostream>
#include <algorithm>
#include <bitset>
#include <cmath>
#include <vector>
const int N = 5e5 + 7, M = 25;

typedef Modint<998244353> mi;

namespace wyx {

mi phi[M];
class PrimeSieve {
	std::bitset<M> ip;
	std::basic_string<int> pr;
public:
	PrimeSieve(int n) {
		phi[1] = 1;
		for(int i = 2; i < n; ++i) {
			if(!ip[i]) pr += i, phi[i] = i - 1;
			for(int& j: pr) {
				if(i * j >= n) break;
				ip[i * j] = 1;
				if(i % j == 0) {
					phi[i * j] = phi[i] * j;
					break;
				}
				phi[i * j] = phi[i] * (j - 1);
			}
		}	
	}
} PS(M);

struct data { int x, sq, d; };
std::vector<data> g;

int n, m, L, freq[N];
mi dp[M][N], inv[M];
inline void main() {
	std::cin >> n >> m;
	int maxw = 0, minw = 1e9;
	for(int x, i = 1; i <= n; ++i) {
		std::cin >> x, ++freq[x];
		maxw = std::max(maxw, x);
		minw = std::min(minw, x);
	}
	L = std::floor(logl(m) / logl(minw));
	for(int i = 1; i <= L; ++i) inv[i] = mi(i).inv();
	dp[0][1] = 1;
	for(int i = 1; i <= L; ++i) {
		for(int j = minw; j <= maxw; ++j) {
			if(!freq[j]) continue;
			int upbound = m / j;
			for(int k = 1; k <= upbound; ++k) {
				dp[i][k*j] += dp[i-1][k] * freq[j];
			}
		}
	}
	for(int i = 2; 1ll * i * i <= m; ++i) {
		for(i64 j = 2, k = i * i; k <= m; ++j, k *= i) {
			g.push_back(data{(int)k, i, (int)j});
		}
	}
	std::sort(g.begin(), g.end(), [](auto&& x, auto&& y) {
		return x.x > y.x;
	});
	for(int x = 2; x <= m; ++x) {
		mi ans = 0;
		for(int k = 1; k <= L; ++k) {
			ans += inv[k] * phi[1] * dp[k][x];
		}
		while(!g.empty() && g.back().x == x) {
			auto& [__, sq, d] = g.back(); g.pop_back();
			for(int k = d; k <= L; k += d) {
				ans += inv[k] * phi[d] * dp[k / d][sq];
			}
		}
		std::cout << ans << " ";
	}
}

};

int main() {
	std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
	wyx::main();
}

例题:P4980【模板】Pólya 定理

\(n\) 种颜色给长为 \(n\) 的环染色,仅通过旋转重合的方案被认为相同,求本质不同方案数,\(n\le 10^9\)

定义 \(Y=\{C_1,C_2,\cdots,C_n\}\) 表示所有的颜色。

\(X\) 表示环上的 \(n\) 个点表示的集合。

\(G=(\{\) 顺时针旋转 \(i\) 个单位 \(| 0\le i < n\},\)操作复合\()\)

由 Pólya 定理直接得出答案为:

\[\dfrac 1n \sum_{i=1}^nn^{\gcd(i,n)}=\dfrac 1n\sum_{d|n}n^d\varphi(\dfrac nd) \]

posted @ 2025-10-23 22:15  CuteNess  阅读(11)  评论(0)    收藏  举报