集合幂级数——FWT与FMT
集合幂级数,可以理解为类似多项式的一个东西,将集合的子集视作二进制数,表示这一项的“次数”。
之所以加双引号,因为这并不是严格意义下的次数,而是为了方便理解它的卷积的一个概念。
一种严格定义是,一个全集的所有子集到某个域上的映射。
接下来,为了方便,用整数表示集合。尽量用比较通俗的方式讲。
基础——与和或#
集合并卷积。
FMT 和 FWT 几乎一样,其实就是高维前缀和。一个是分治一个是 DP。
FMT#
有 \(C_i=\sum\limits_{j\oplus k=i}A_jB_k\),其中 \(\oplus\) 为与、或。
构造 \(FMT[S]_i=\sum\limits_{j\oplus i=i}S_j\),有
于是进行一次高维前缀和,计算出 \(FWT[A]\) 与 \(FWT[B]\),每个位置相乘得到 \(FWT[C]\),然后再差分回来。
FMT 因为是 DP 形式,所以更加灵活, \(N\) 无需为 \(2\) 的次方。
FWT#
有 \(C_i=\sum\limits_{j\oplus k=i}A_jB_k\)。
定义 \(S\ \mathrm{link}\ T\) 表示序列 \(S\) 连接上序列 \(T\),\(S\) 与 \(T\) 的四则运算表示序列 \(S,T\) 每一项分别相加/减/乘/除。
构造 \(FWT[S]_i=\sum\limits_{j\oplus i=i}S_j\),其中 \(\oplus\) 为或,有
计算出 \(FWT[A]\) 与 \(FWT[B]\),每个位置相乘得到 \(FWT[C]\),如果要从 \(FWT[C]\) 变回来,只要把上式中的 \(+\) 改为 \(-\) 即可。
\(\oplus\) 为与的情况只要把所有东西都反过来即可。
其实 FWT 和 FMT 的代码很像,只是 FWT 是分治思想,每次加入下标的一个二进制位。
重难点——异或与同或#
集合对称差卷积。
定义 \(P(i,j,\oplus)\) 表示 \(\mathrm{popcount}(i \oplus j)\bmod2\),构造 \(FWT[S]_i=\sum\limits_{P(j,i,\oplus)=0}S_j-\sum\limits_{P(j,i,\oplus)=1}S_j\),其中 \(\oplus\) 为与,有
从 \(FWT[C]\) 变回来,就是上述式子除以 \(2\)。同或的情况类似。
这个东西的证明是,\(P(j\ \mathrm{xor}\ k,i,\mathrm{and})=P(j,i,\mathrm{and})\ \mathrm{xor}\ P(k,i,\mathrm{and})\),因此
All Last——子集卷积#
下面的 \(FWT\) 可以替换成 \(FMT\)。
求 \(C_i=\sum\limits_{j\ \mathrm{or}\ k\ =i,j\ \mathrm{xor}\ k\ =\ i}A_jB_k\)。
第一个限制直接集合并卷积。第二个限制也就是 \(\mathrm{popcount}(j)+\mathrm{popcount}(k)=\mathrm{popcount}(i)\)。
定义 \(FWT[C,i]\) 为 \(C\) 中所有表示的集合的大小为 \(i\) 的位置的 \(FWT\)。
\(A,B\) 先分别做 \(\log\) 次(即集合大小)集合并卷积,每次将大小相同的子集卷起来,
再做 \(\log^2\) 次序列单点相乘得到 \(FWT[C,i]\)(这是一个普通卷积),最后把 \(\log\) 个 \(FWT[C,i]\) 逆回去。
这样就做完了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】