快速沃尔什变换-FWT
0. 引入
快速沃尔什变换(FWT)
是用来解决位运算卷积的算法,形如:
其中,\(\oplus\) 代表位运算中的某一种
1. 转化
回顾 FFT/NTT
,加法卷积是将表达式转化成点值,相乘后再转化回来
那我们考虑构造一个幂级数,使其与点值有类似的功能,即:
我们考虑设 \(c(i,j)\) 为转换系数,满足
由 \(FWT(A)_i\times FWT(B)_i=FWT(C)_i\),我们需要:
根据 \(C_k=\sum_{i\oplus j=k}A_i\times B_j\),有
这说明,我们需要构造出 \(c\) 满足 \(c(i,j)c(i,k)=c(i,j\oplus k)\)
同时,\(c\) 应该还要满足一个条件:我们假设对于一个二进制数 \(a\),它从高到低位表示为 \(a_0,a_1,a_2,...\)
那么应该有 \(c(i,j)=c(i_0,j_0)c(i_1,j_1)c(i_2,j_2)...\)
这样,我们就可以推出 \(c(i_x,j_x)c(i_x,k_x)=c(i_x,j_x\oplus k_x)\Leftrightarrow c(i,j)c(i,k)=c(i,j\oplus k)\)
因此,假设我们构造出了 \(c(0,0),c(0,1),c(1,0),c(1,1)\),我们看一下如何求解 \(FWT(A)\)
我们考虑按位折半
设 \(i'\) 表示 \(i\) 去掉二进制首位(包括 \(0,1\))的数,就有:
说明我们可以将问题分治下去,同时我们要构造一个矩阵:
而且这个矩阵有逆,用于 IFWT
我们假设分治到求长度为 \(n\) 的 FWT
,\(A_0\) 表示二进制首位为 \(0\) 的幂级数(即已经求出的长为 \(n/2\) 的 FWT
),\(A_1\) 同理
有:
2. 构造
接下来我们就要学习怎么构造位矩阵(记结论!)
① 或(or)卷积
由定义,我们有:
所以 \(c(0,0)=0/1\)
同理 其他都只能取 \(0/1\)
然后又需要满足:
因为如果存在某一行或某一列都为 \(0\) 时,矩阵没有逆,所以我们只有这两种构造:
我们选用第二个矩阵,其逆矩阵为:
运算为:
逆运算为:
② 和(and)卷积
同上,我们有:
所以 \(c(x,y)=0/1\)
所以有两种矩阵:
依旧取第二个矩阵,其逆为:
运算为:
逆运算为:
③ 异或(Xor)卷积
有以下关系式:
所以 \(c(0,0)=c(1,0)=1\),其他的为 \(1/-1\)
所以有:
继续选用第二个矩阵,其逆为:
运算为:
逆运算为:
然后我们就可以做了!
FWT
有是线性变换,也就是说它有如下性质:
3. 例题
① CF449D Jzzhu and Numbers
这是一个且
背包,我们有转移方程为:
我们就可以构造出 \(n\) 个函数(设 \(Mx = \max(a_i)\),\(m\) 为最小的满足 \(2^m-1\ge Mx\) 的正整数),第 \(i\) 个函数为:\(f_i[2^m-1]=f_i[a[i]]=1\),其余系数为 \(0\)
\(f_i[2^m-1]=1\) 表示 \(a[i]\) 不选的情况
我们将这些函数全部卷起来后,\([x^0]\) 上的系数就是答案
但直接卷的复杂度是 \(O(n^2\log n)\) 的,还不如原来的 \(O(n^2)\) 直接做
我们注意到,每个函数都只有两项为 \(1\),我们可以考虑进行一些优化
由于我们是 and卷积
,选择的矩阵为 \(\begin{bmatrix}
1 & 1\\
0 & 1
\end{bmatrix}\)
所以有 \(c(i,j)=[i\&j=i]\)
这说明,\(c(k,2^m-1)\) 一定为 \(1\),而 \(c(k,a_i)\) 只有当 \(k\& a_i=k\) 时才会为 \(1\)
我们再考虑设 \(F_k=\prod_{i=1}^{n}FWT(A_i)_k\)
那么 \([x^0]IFWT[F]\) 的系数就是答案
所以,\(F_k\) 一定为 \(2\) 的整次幂
我们的任务就是统计有多少个 \(2\) 相乘
实际上,\(a_i\)会对它的子集进行贡献
所以,我们可以通过子集求和,也就是做高维后缀和来求,然后再求 IFWT
即可
还有一种方法,我们设 \(G[a_i]\) 为 \(a_i\) 出现的次数,求出 \(FWT(G)\),那么 \(FWT(G)_k\) 就是 \(F_k\) 上 \(2\) 的个数
证明:
-
\[FWT(G)_k=\sum_{j=0}^{2^m-1}c(k,j)G[j]=\sum_{j=0}^{2^m-1}c(k,j)\sum_{i=1}^{n}[a_i=j]=\sum_{i=1}^nc(k,a_i) \]
(这两种方法的复杂度相同,但可以看出还是高维前缀和略胜一筹)
② UOJ310 黎明前的巧克力
依然考虑 DP
,有转移方程:
构造 \(n\) 个函数,使 \(F_i[0]=1,\ F_i[a[i]]=2\)
直接卷依旧是 \(O(n^2\log n)\) 的
对于每个函数,有 \(FWT(F_i)[k]=\sum_{j=0}^{lim}c(k,j)F_i[j]\)
有 异或卷积
矩阵的性质,我们知道:
所以原式有 \(FWT(F_i)[k]=1+(-1)^{pop\_cnt(k\&a[i])}\times 2\)
那么就可能取 \(-1\) 或 \(3\)
由于 FWT(A+B)=FWT(A)+FWT(B)
,我们可以考虑将 \(n\) 个函数相加得到一个函数 \(G\),变换为 FWT
后,我们就有 \(FWT(G)[k]=\sum_{i=1}^n FWT(F_i)[k]\)
由于我们原答案需要的是 \(\prod_{i=1}^n FWT(Fi)[k]\),我们可以解出 \(-1,3\) 的个数后,通过快速幂求出
③ CF1119H Triple
套路是类似的,但还有新思想在里面
我们仍是设 \(n\) 个函数,对于第 \(i\) 个函数,我们设 \(F_i[a_i]=x,\ F_i[b_i]=y,\ F_i[c_i]=z\)
我们考虑将它们卷起来,得到第 \(i\) 位上的系数就是答案为 \(i\) 的值
一样套路,因为只有 \(a_i,b_i,c_i\) 上有值,所以转化为
类似上一题,我们这时候有 \(8\) 种取值
当然,这其实是可以做的,但实在是太麻烦了,我们考虑减少一些分类情况
我们考虑对每一对三元组 \((a_i,b_i,c_i)\),每个数都异或上 \(a_i\),也就是得到 \((0,b_i\oplus a_i, c_i\oplus a_i)\)
这样说明我们默认选择了 \(a_i\),但如果我们选择 \(b_i\oplus a_i\) 或者 \(c_i\oplus a_i\),就相当于选择 \(b_i,\ c_i\),这与原问题等价(最后输出第 \(i\) 个答案时应为 \(ans[i\oplus sum]\),其中 \(sum=a_1\oplus a_2\oplus ...\ a_n\))
这样 \(x\) 前面 的取值就为 \(1\)
就有 \(4\) 种情况:
设\(FWT(S)[k]=\prod_{i=1}^n FWT(F_i)[k]\),每种取值各有 \(c_1,c_2,c_3,c_4\) 个(\(S\) 就是最终答案)
那么首先应有:
我们考虑再构造出 \(3\) 个等式
- 我们设 \(n\) 个函数,第 \(i\) 个函数 \(G_i[b_i]=1\),也就是 \(x=0,y=1,z=0\)
我们考虑将求 \(FWT(G_i)\),就有 \(FWT(G_i)[k]=(-1)^{pop\_cnt(k\&b_i)}\)
我们考虑求 \(FWT(\sum_{i=1}^n G_i)\),那么其实有 \(FWT(\sum_{i=1}^n G_i)[k]=\sum_{i=1}^n (-1)^{pop\_cnt(k\&b_i)}\),设为 \(p_1\)
就能得到 \(p_1=c_1+c_2-c_3-c_4\)
- 同理,我们再设 \(n\) 个函数,第 \(i\) 个函数 \(G_i[c_i]=1\),也就是 \(x=0,y=0,z=1\)
也就有 \(FWT(\sum_{i=1}^n G_i)[k]=\sum_{i=1}^n (-1)^{pop\_cnt(k\&c_i)}\),设为 \(p_2\)
即 \(p_2=c_1-c_2+c_3-c_4\)
- 我们再构造 \(n\) 个函数,第 \(i\) 个函数 \(G_i[b_i\oplus c_i]=1\),也就是将我们前面设的式子,第 \(i\) 个对着卷上第 \(i\) 个
就有 \(FWT(\sum_{i=1}^n G_i)[k]=\sum_{i=1}^n (-1)^{pop\_cnt(k\&b_i)}(-1)^{pop\_cnt(k\&c_i)}\),设为 \(p_3\)
即 \(p_3=c_1-c_2-c_3+c_4\)
这样我们就得到了:
解方程就能得到
最后我们再按照上一题,求幂,IFWT
就可以求出答案了!