集合幂级数 学习笔记
FMT / FWT
前置概念
与加法域类似,定义 \(\mathbb{F}_{V}\) 下的多项式为 \(f(x)=\sum\limits_{i=0}^{2^V-1} f_i x^i\),满足运算律 \(x^i\times x^j=x^{i\oplus j}\),其中 \(\oplus\) 为一种位运算。
定义集合卷积(叉乘)为:\((f*g)_k=\sum\limits_{i\oplus j=k} f_i\times g_k\)。现在我们想要快速计算集合卷积。
令 \(h=f*g\),假设我们可以设计一种线性变换 \(f\to \hat{f}\),使其满足 \(\hat{h}=\hat{f}\cdot \hat{g}\),其中 \(\hat{f}\cdot \hat{g}\) 表示点乘,即变换满足 \(\hat{h}_i=\hat{f}_i\times \hat{g}_i\)。那么计算 \(f*g\) 时,可以先求出 \(f,g\) 的变换 \(\hat{f},\hat{g}\),然后点乘得到 \(\hat{h}=\hat{f}\cdot \hat{g}\),最后做逆变换用 \(\hat{h}\) 还原出 \(h\)。
FMT / FWT 就是用来计算这个变换的。以三种运算符 OR,AND,XOR 为例。
其中三者都可以使用 FWT 变换,OR,AND 可以用 FMT 变换,XOR 没有 FMT 变换。
OR,AND 运算的 FMT 变换
以 OR 为例,给出结论:\(\hat{f}_i=\sum\limits_{j\subseteq i} f_j\),也就是说 OR 的 FMT 变换就是子集和。
逆变换:\(f_i=\sum\limits_{j\subseteq i} (-1)^{|i|-|j|}\hat{f}_j\),也就是子集反演的式子。
如何理解?考虑原来的条件是 \(i\cup j=k\) 太严格了,不妨放宽限制计算 \(i\cup j\subseteq k\),发现这个条件等价于 \(i\subseteq k\wedge j\subseteq k\),那么两部分就拆开了,可以分别做变换得到子集和 \(\hat{f},\hat{g}\),点乘得到 \(\widehat{f*g}\)。但是这样算重了 \(i\cup j\) 真包含于 \(k\) 的情况,于是用逆变换,也就是子集反演推回去即可去重。
类比这个,容易给出 AND 的 FWT 变换就是超集和,不再赘述。
因此直接做高维前后缀和就能求出 FMT 变换。
XOR(集合对称差卷积) 的变换
给出结论:\(\hat{f}_i=\sum\limits_{j=0}^{2^V-1} f_j\cdot (-1)^{|i\cap j|}\)。这个式子非常重要。
逆变换:\(f_i=\dfrac{1}{2^V}\sum\limits_{j=0}^{2^V-1} \hat{f}_j\cdot (-1)^{|i\cap j|}\)。
本质是 \(|i\cap j|+|i\cap k|\equiv |i\cap (j\oplus k)|\pmod 2\)。
FWT 变换
FWT 变换的思想就是高位分治,也就是按层从上到下分讨当前层 \(0/1\)。假设我们已经求解出了当前位为 \(0/1\) 的变换 \(\hat{f}_0,\hat{f}_1\),直接考虑 \(0\to 0,0\to 1,1\to 0,1\to 1\) 的贡献即可,如何知道了变换的式子就非常好推。
以 XOR 为例。不难发现变换形如 \((\hat{f}_0+\hat{f}_1,\hat{f}_0-\hat{f}_1)\)。那么我们自底向上进行变换即可。
例题
【UNR #2】黎明前的巧克力
如果一个子集 \(S\subseteq [n]\) 的异或和为 \(0\) 则会对答案造成 \(2^{|S|}\) 的贡献。考虑将这个 \(2\) 的贡献拆到每个元素上,考虑集合幂级数,在异或域满足 \(x^i\times x^j=x^{i\oplus j}\),则原问题的答案写成生成函数的形式就是 \([x^0]\displaystyle\prod\limits_{i=1}^n(1+2x^{a_i})\)。令 \(F_i=1+2x^{a_i}\),考虑直接用 FWT 解决,乘积式变成 \(\mathrm{IFWT}(\mathrm{FWT}(F_1)\cdot \mathrm{FWT}(F_2)\cdot \mathrm{FWT}(F_n))\),其中 \(\cdot\) 表示点乘,但是这样要对每个 \(F_i\) 都求出 FWT 数组,无法接受。
考虑 FWT 的定义式,\(\hat{F}_j=\displaystyle\sum_{k=0}^{2^V-1}F_k\times (-1)^{|j\cap k|}\)。取 \(k=0\) 时会对所有 \(i\) 造成 \(1\) 的贡献,取 \(k=a_i\) 时以 \((-1)^{|j\cap k|}\) 系数向 \(j\) 作出 \(2\) 点贡献,也就是说 \(\hat{F}_i\) 中只会有 \(-1,3\) 两种数。因此点乘后序列的第 \(j\) 位可以被表示成 \((-1)^{c_j} 3^{n-c_j}\) 的形式,考虑如何解出 \(c_j\)。
考虑 \(\mathrm{FWT}(F_i)\) 对位相加之后的和 \(G=\mathrm{FWT}(F_1)+\mathrm{FWT}(F_2)+\dots+\mathrm{FWT}(F_n)\),则 \(-x_j+3(n-x_j)=G_j\),解出 \(x_j=\frac{3n-G_j}{4}\),那么我们只需要得到 \(G\) 即可,之所以考虑 \(G\) 是因为 FWT 是线性变换,有 \(G=\mathrm{FWT}(F_1)+\mathrm{FWT}(F_2)+\dots+\mathrm{FWT}(F_n)=\mathrm{FWT}(F_1+F_2+\dots+F_n)\)。于是就做完了,我们计算出 \(F_1+F_2+\dots+F_n\) 进行一次 FWT 变换得到 \(G\),以此反求出 \(c_j\),进而得到点乘后序列的第 \(j\) 位是 \((-1)^{c_j}3^{n-c_j}\),再做一遍 IFWT 就行了。
子集卷积,集合幂级数 exp/求逆
子集卷积
就是要计算 \(h_S=\displaystyle\sum_{L\cup R=S,L\cap R=\emptyset} f_L\cdot g_R\)。显然有一个枚举子集的 \(O(3^n)\) 做法。
把后者的条件转化成 \(|L|+|R|=|L\cup R|\)。考虑加入一个辅助元 \(u\) 变成二元多项式 \(F(u,x)\),其中 \([u^ix^S]F=[x^S]f_S\cdot [|S|=i]\),重新对这个二元多项式定义子集卷积,在第一维上体现为和卷积,在第二维上体现为或卷积,即 \(F_{u,S}\times G_{v,T}\to H_{u+v,S\cup T}\)。不妨将 \(u\) 当做主元,对 \(x\) 维进行 FWT 变换,这样 \(x\) 维的卷积也退化成了点乘:\(\widehat{F}_{u,S}\times \widehat{G}_{v,S}\to \widehat{H}_{u+v,S}\)。这样每个 \(S\) 也独立了,相当于对 \(\widehat{F}_{*,S}\) 和 \(\widehat{G}_{*,S}\) 做形式幂级数的卷积(加乘卷积),在这里直接暴力贡献 \(\widehat{F}_{i,S}\times \widehat{G}_{j,S}\to \widehat{H}_{i+j,S}\),没有 NTT 的必要因为瓶颈不是这个。求完之后再对每个 \(\widehat{H}_i\) 用 IFMT 还原即可,最后的答案为 \(h_S=H_{|S|,S}\),表示卷积过程中满足 \(|L|+|R|=|S|\)。
时间复杂度优化到了 \(O(2^nn^2)\)。
集合幂级数 \(\exp\)
由麦克劳林级数定义,展开式为 \(\exp(F(x))=\displaystyle\sum_{n\ge 0} \frac{F^n(x)}{n!}\),其中乘法定义为子集卷积。
如果将 \([x^S]F(x)\) 视作集合 \(S\) 的权值,直接瞪就可以发现 \([x^S]\exp(F(x))\) 的组合意义就是把集合 \(S\) 进行无序子集划分的权值和,划分方案的权值定义为子集的权值之积。感性理解一下,如果能划分空集就完蛋了,因此限制 \([x^{\varnothing}]F(x)=0\),同时有 \([x^{\varnothing}]\exp(F(x))=1\)。我们可以得到 \(\exp\) 的表达式:
直接套用子集卷积的做法即可,引入辅助元 \(u\),设 \([u^ix^S]F=[x^S]f_S\cdot [|S|=i]\)。
对 \(F(u,x)\) 定义 \(\exp(F(u,x))=\displaystyle\sum_{n\ge 0} \frac{F^n(u,x)}{n!}\), 乘法运算律为 \(u^ix^S\times u^jx^T\to u^{i+j}x^{S\cup T}\)。
对 \(x\) 维做 FMT 后,运算律变成 \(u^ix^S\times u^jx^S\to u^{i+j}x^S\),每个 \(S\) 独立,得到:
固定住 \(S\) 这一维,相当于在 \(\widehat{F}_{*,S}\) 上做形式幂级数上的 \(\exp\)。有 \(O(n^2)\) 的递推方法求 \(\exp\)。
设 \(g(x)=\exp(f(x))\),两边同时求导得 \(g^\prime(x)=g(x) f^\prime(x)\)。比较两边的 \(x^n\) 系数:
对每个 \(S\) 做这个 \(O(n^2)\) 递推即可。时间复杂度 \(O(2^nn^2)\)。
这个做法要求 \(1\sim n\) 都有逆元。
集合幂级数求逆
跟上面的一样,只需要整出一个形式幂级数下的求逆即可。
令 \(g(x)\) 为 \(f(x)\) 的逆,可以得到 \(g(x)f(x)=1\),也就是只有 \([x^0]f(x)g(x)=1\),其余为 \(0\)。
因此边界为 \(g_0=\frac{1}{f_0}\),其余项由递推式给出:

浙公网安备 33010602011771号