集合幂级数 exp
求 \(e^{F(x)} = \sum\limits_{i \ge 0} \dfrac{F(x)^i}{i!}\),其中若 \(S \cap T = \varnothing\),则 \(x^S \times x^T = x^{S \cup T}\)。
定义二元函数 \(F(x, y) = \sum x^S y^{|S|} a_S\),这样可以消除 \(S \cap T = \varnothing\) 的限制。此时 \(x^S y^i \times x^T y_j = x^{S \cup T} y^{i + j}\),即一维是集合的并,一维是加法。
对 \(x\) 维做 FWT,此时 \(x\) 维变成点乘,即 \(x^S y^i \times x^S y^j = x^S y^{i + j}\)。此时 \(x\) 维独立,对 \(2^n\) 个 \(n\) 次多项式做 exp 即可。
\(O(n^2)\) 算 exp:\(e^{F(x)} = G(x)\),求导有 \(F'(x) G(x) = G'(x)\),对比系数可以求出 \(G(x)\)。
集合幂级数 ln
求 \(\ln F(x) = \sum\limits_{i \ge 1} (-1)^{i - 1} \dfrac{(F(x) - x^{\varnothing})^i}{i}\)。
与 exp 类似。
集合幂级数求逆
求 \(G(x)\) 满足 \(F(x) G(x) = x^{\varnothing}\)。
通过询问 ChatGPT 可知 \(\frac{1}{x} = \sum\limits_{i \ge 0} (1 - x)^i\),所以沿用 exp 和 ln 的方法即可。
半在线子集卷积
给定 \(g\),对所有 \(S\) 计算 \(f_S = \sum\limits_{T \subseteq S, T \ne \varnothing} g_T f_{S \setminus T}\)。
按照 \(k = |S| = 1, 2, \ldots, n\) 依次计算对应的 \(f_S\)。引入二元函数 \(F_{i, S} = [|S| = i] f_S\)。做到 \(k\) 时 \(|T| < k\) 的贡献已经计算完毕,将 \(F_{k, \ast}\) 做 iFWT 即可。最后再加上 \(g_S\) 对 \(f_S\) 的贡献。然后再对 \(F_{k, \ast}\) 做 FWT,贡献累加到 \(F_{i + k, \ast}\) 的 FWT 数组。
集合幂级数 exp(非素数模数)
考虑 \(O(3^n)\) 算 exp 的方法 \(f_S = \sum\limits_{T \subseteq S, T \ne \varnothing, \operatorname{lowbit}(T) = \operatorname{lowbit}(S)} g_T f_{S \setminus T}\)。总体和半在线子集卷积流程一样,但是我们需要将 \(g\) 的 FWT 和 \(f\) 的 iFWT 做一些改动。具体地,变换时不转移 \(S\) 的最低位。
集合幂级数 ln(非素数模数)
根据组合意义我们有 \(f_S = g_S - \sum\limits_{T \subseteq S, T \ne \varnothing, \operatorname{lowbit}(T) = \operatorname{lowbit}(S)} f_T g_{S \setminus T}\)。套用上述 exp 做法即可。
多项式复合集合幂级数
其实是集合幂级数 exp / ln 的一般化问题:给定 \(a_0, a_1, \ldots, a_n\) 和集合幂级数 \(F(x)\),保证 \([x^{\varnothing}] F(x) = 0\),求 \(\sum\limits_{i = 0}^n a_i F(x)^i\)。
对于集合幂级数 \(F(x)\),\([x^S] F(x)^i\) 的含义是,将 \(S\) 无序地划分成 \(T_1 \sqcup T_2 \sqcup \ldots \sqcup T_i\),定义一个划分方案的权值为 \(i! \prod\limits_{j = 1}^i [x^{T_j}] F(x)\),\([x^S] F(x)^i\) 就是所有划分方案的权值和。
考虑利用这个组合意义 DP。设 \(f_{i, j, S}\) 为,当前考虑了最低的 \(i\) 位,之后还要选择 \(j\) 个集合,已经选择的集合的并是 \(S\),划分的权值和。
初值有 \(f_{0, i, \varnothing} = a_i \times i!\)。转移是 \(f_{i, j, S} = f_{i - 1, j, S} + \sum\limits_{\operatorname{highbit}(T) = i, T \subseteq S} f_{i - 1, j + 1, S \setminus T} \times b_T\),其中 \(b_S = [x^S] F(x)\)。转移的意义是选或不选以 \(i\) 为最高位的一个集合。
这个转移可以子集卷积优化。时间复杂度 \(O(\sum\limits_{i = 1}^n (n - i) i^2 2^i)\),通过询问 ChatGPT 老师可知这个的量级是 \(O(n^2 2^n)\),但是常数显然很大。
例题
1. LOJ6673 EntropyIncreaser 与山林
集合幂级数题的套路是:先不考虑连通,得到的答案再求 \(\ln\) 就是考虑连通的答案。
考虑如何计算一个点集内有多少边集满足所有点度数是偶数。每个连通块单独考虑,任取一棵生成树,非树边任意选择,那么会存在唯一一种选择树边的方案,所以方案数就是 \(2^{m - n + 1}\)。对于不连通的情况,每个连通块求和可得方案数是 \(2^{m - n + c}\),其中 \(c\) 为连通块个数。
然后我们得到了 \(F(x)\),答案即为 \([x^U] \ln F(x)\)。
时间复杂度 \(O(n^2 2^n)\)。
2. LOJ154 集合划分计数
使用 多项式复合集合幂级数 方法即可。
时间复杂度 \(O(n^2 2^n)\)。
3. PTZ Winter 2020 Day 9 Yuhao Du Contest 7 F Fast as Ryser
第一步是一个很牛的转化:首先将点数补全到偶数,然后连边 \((2i, 2i + 1)\),那么最后每个连通块都是点数为偶数的环或者链。
将一个 \((2i, 2i + 1)\) 看做一个组,写一个 DP 计算对于一个组的子集,形成环或链的方案数。设环的集合幂级数为 \(F(x)\),链的为 \(G(x)\),答案即为 \([x^U] e^{F(x) + G(x)}\)。
时间复杂度 \(O(n^2 2^\frac{n}{2})\)。