FWT (快速沃尔什变换)详解 以及 K进制FWT
FWT (快速沃尔什变换)详解 以及 K进制FWT
约定:$F’=FWT(F)$
卷积的问题,事实上就是要构造$F’G’=(FG)’$
我们常见的卷积,是二进制位上的or ,and ,xor
但正式来说,是集合幂指数 上的 并 , 交 , 对称差
为了说人话,这里就不带入集合幂指数的概念了
一个常识:$\sum_{T\sube S}(-1)^{|T|}=[S=\empty]$
or 和 and 卷积
ps: 虽然这两个并不是$\text{FWT}$,应该叫$\text{FMT}$(快速莫比乌斯变换),但是由于常用的是这3个,所以放到一起
这两种卷积的本质是相同的,所以只解释$or$卷积
or卷积的本质就是高位前缀和
即:$F’_S=\sum _{T\sube S}F_T$
正确性:
即$\forall S,F’_S \cdot G’_S=(F\cup G)’_S$
左边=
$F’_S \cdot G’_S=\sum _{T\sube S}\sum _{R\sube S}F_T\cdot G_R$
右边=
$(F\cup G)’_S=\sum_{T\sube S}(F \cup G)_S$
$=\sum_{T\sube S}\sum_{A,B,A\cup B=S}F_A\cdot G_B$
$=\sum_{T \sube S}\sum_{R \sube S}F_T \cdot G_R$
卷积实现
其实第一次层循环的意思是枚举子集中和自己不同的位最高是$i$
让$0$向$1$转移即可
1 | void FWT(int n,ll *a){ |
Tips:如果要卡常,可以写成类似$\text{FFT}$的形式,因为优化了访问顺序会快一些
实现逆卷积
把上面的加换成减,这是一个类似容斥的东西
但是因为是反解,所以这个过程我么通常称为子集反演
那么每次$0$向$1$的转移意味着多了一个不同的位置
设$F’_S=\sum_{T\sube S}F_T$
实际逆卷积就是$F_S=\sum_{T\sube S}(-1)^{|T\oplus S|} F’_S$
证明如下:
$\Leftrightarrow F_S=\sum_{T\sube S}(-1)^{|T\oplus S|} \sum _{R\in T}F_R$
$\Leftrightarrow F_S=\sum_{T\sube S}F_R\sum _{T\sube R,R\sube S}(-1)^{|S\oplus R|}$
$\Leftrightarrow F_S=\sum_{T\sube S}F_R\sum _{R\sube (S\oplus T)}(-1)^{|R|}$
带入上面所提到的$\sum_{T\sube S}(-1)^{|T|}=[S=\empty]$,成立
1 | void FWT(int n,ll *a,int f){ |
应用 : 子集卷积(可以看luogu)
问题描述: 给定$F_S,G_T$,求出$H_{R}=\sum_{S\cup T=R,S\cap T=\empty}F_S\cdot G_T$,设有$2^n$个元素
我们知道直接枚举的复杂度为$O(3^n)$
直接应用or卷积无法保证$S\cap T=\empty$,但是可以再记录一个占位数量,即把$F,G$按照每一位包含1的数量分开成$n+1$部分,卷积完成之后
应该满足1的个数恰好为两者之和,否则清空
需要$n$次卷积,$n^2$次转移,因此复杂度为$O(n^22^n)$,在渐进意义上更优于$O(3^n)$
Xor 卷积
这里要用到一个小性质
$|A\cap B|+|A\cap C|\equiv |A\cap (B\bigoplus C)| \pmod 2$
思路介绍:
我们是要构造一个$F_S\rightarrow G_T$的变换,使得该变换满足Xor的性质,且能在较优的时间复杂度内完成,并且能够在较优的时间内完成反演
由于上面的这条式子,考虑可以构造$F’_S=\sum_{T}(-1)^{|S\cap T|}F_T$,这样$(-1)^k$的系数在$\mod 2$意义下可以抵消
正确性
即$\forall S,F’_S \cdot G’_S=(F\bigoplus G)’_S$
$F’_S\cdot G’_S=\sum_{T} \sum_{R}(-1)^{|S\cap T|+|S\cap R|}F_T\cdot G_R$
$=\sum _T\sum _R(-1)^{|(T\bigoplus R)\cap S|}F_T\cdot G_R$
显然这个式子与右边相同
卷积实现
考虑和前面相同的方法,枚举二进制位上最高的$1$
之前由于转移是单向的,所以只需要一次加法,这里由于有了系数同时还是双向的转移,所以要格外注意
转移系数也是比较明显的
$0\rightarrow 0 = 1$
$0\rightarrow 1 = 1$
$1\rightarrow 0 = 1$
$1\rightarrow 1 = -1$
1 | void FWT(int n,ll *a){ |
实现逆卷积
考虑再卷一次
$F’’_S=\sum_T\sum_R(-1)^{|S\cap R|+|T\cap R|}F_T$
$=\sum_T \sum_R (-1)^{|(S\bigoplus T)\cap R|}F_T$
$\because \sum_T (-1)^{|S\cap T|}=\sum_{T\sube S}(-1)^{|T|}2^{|U|-|S|}=[S=\empty]2^{|U|-|S|}$(其中$U$是全集)
$\therefore F’’_S=\sum_S2^{|U|}F_S$
所以逆卷积就是再卷一遍,最后除去$n$即可
1 | void FWT(int n,ll *a,int f){ |
和上面一样的,可以写成类似$\text{FFT}$的形式卡常
拓展 K - FWT
实际上学习了这个拓展能让你更好地理解$\text{FWT}$
不妨考虑$n$个维度的情况,每个维度是一个$0,1,\cdots k-1$中的数
由于$k$进制下不好用集合描述,因此考虑用一个向量$\vec{V}=\lbrace V_0,V_1,\cdots,V_{n-1}\rbrace,V_i\in[0,k-1]$表示
一个多项式可以具象地用$0,1,\cdots,k^n-1$这个$k^n$个位置上的系数表示
$\text{and,or}$卷积在$k$进制下可以拓展为按位取$\min,\max$,这个直接累前缀和就可以了,不作赘述
而$k$进制下的$\text{xor}$可以扩展为两个向量列的取模加法
$\vec{A}+\vec{B}=\vec{C},C_i=(A_i+B_i)\bmod k$
也可以描述为不进位的$k$进制数加法
其实用$\text{K-FWT}$称呼这个似乎不是很形象,更好的可以称之为$\text{n-DFT}$
也就是说$\text{K-FWT}$实际上就是在$n$个维度上分别做大小为$k$的循环卷积,使用一种结合$\text{FWT-DFT}$的方法(因此需要用到$k$次单位根$\omega_k$)
卷积构造
原多项式$F$向卷积多项式$F’$的转换系数为$[x^A]F\rightarrow [x^B]F’:\omega_k^{A\cdot B}$
其中$A\cdot B$为向量内积,即$\sum A_i\cdot B_i$
从中也可以很好地看到$\text{xor}$卷积的影子
实现方法上,可以依次枚举$0,1,\cdots,n-1$每一位,将除了这一位上都相同的数取出来
按照这一位上的值做一次$\text{DFT}$
需要$n$位枚举,每次枚举需要做$k^{n-1}$次$k^2$的$\text{DFT}$,因而复杂度为$O(nk^{n+1})$
对于$k$比较大的情况,如果$k=2^t$可以直接用$\text{FFT/NTT}$,否则还可以参考这个
可以优化到$O(nk^n\log k)$
逆卷积
当然是换成$\text{IDFT}$,最后全部除掉$k^n$
正确性上,如果你对于$\text{IDFT}$的原理(单位根反演) 有所了解,就能发现
只有所有位置上都相同的情况才会转移出$k^n$的系数
1 | int w[20]; // 单位根的幂次 |