FWT(快速沃尔什变换)
FWT(快速沃尔什变换)
前言
萌新刚学多项式 1ms,有误或者不严谨指出欢迎指出,感谢大佬!
参考
鸽掉的介绍,我是 OIer 诶,不是 MOer 啊,要这么多证明干什么!直接背代码好了!写多了自然就理解了啊!
简介
使用类似 FFT 的方法求位运算卷积。
我们熟知的多项式卷积是求 \(\sum_{i=1}^n a_i b_{n-i}\)。
对于位运算 \(\oplus\),可以是 or,and,xor。其卷积大概是 \(\sum_{i=1}^n \sum_{i \oplus j = n} a_i b_j\)。
比如或卷积是 \(\sum_{i=1}^n \sum_{i|j = n} a_i b_j\),也就是我们常说的枚举子集。
对于 \(c_n = \sum_{i=1}^n \sum_{i \oplus j = n} a_i b_j\),我们要求出 \(c_n\) 或者 \(\{c_i\}\),最朴素的暴力枚举 \(i,j\) 时间复杂度是 \(O(n^2)\) 的。考虑使用 FWT 优化到 \(O(n \log n)\)。
算法流程
记对序列 \(A=\{a_i\}\) 进行 FWT 变换后的序列(形式幂级数)是 \(fwt(A)\)。
\(A,B,C\) 均指序列,\(a_i\) 之类是序列的第 \(i\) 项(从 \(0\) 开始记下标)。\(fwt(A)\) 之类是序列,\(fwt(A)_i\) 之类是指序列的第 \(i\) 项(同样从 \(0\) 开始记下标)。
我们要构造 \(A \oplus B = C \Longleftrightarrow fwt(A) \cdot fwt(B) = fwt(C)\)。需要再 \(O(n \log n)\) 的时间复杂度内计算 \(A \to fwt(A)\) 和 \(fwt(A)\to A\),和线性求出 \(fwt(A) \cdot fwt(B) = fwt(C)\)。
其中 \(A \oplus B = C\) 指 \(c_n = \sum_{i \oplus j = i} a_i b_j\),即位运算卷积。
\(fwt(A) \cdot fwt(B) = fwt(C)\) 指 \(fwt(C)_n = fwt(A)_n fwt(B)_n\),即点值相乘。
至于为什么要这么定义我还不知道,但是这么定义是可以做的
设 \([i,j]\) 表示 \(a_j\) 对 \(fwt(A)_i\) 的贡献系数。应该有 \([i,j] \in \{0,1\}\)。
即 \(fwt(A)_i=\sum_{j=0}^i [i,j] a_j\)。
我们需要知道 \([i,j]\) 是什么,即如何构造 \(fwt(A)\)。
由于 \(A \oplus B = C\),我们有 \(c_n = \sum_{i \oplus j = i} a_i b_j\)。
因此我们只需要保证对于所有的 \([i,p]=1\) 当且仅当 \(j \oplus k = p\) 的时候 \([i,j]=[i,k]=1\)。
因为是位运算,我们只需要分别考虑每一位就好。即考虑 \([0,0],[0,1],[1,0],[1,1]\) 的取值。每种位运算都是不同的取值。
\(fwt(A)_i=\sum_{j=0}^i [i,j] a_j\),快速根据 \(A\) 求 \(fwt(A)\)。
code
不能理解,不是很好背诵。又学不会,又背不会,真是文理兼废,怎么办呢?
函数:
void calc() { rep(i,0,n-1) _mul(a[i],b[i]); }
void OR(int *f,int x=1) {
for(int o=2,k=1; o<=n; o<<=1,k<<=1)
for(int i=0; i<n; i+=o)
rep(j,0,k-1) _add(f[i+j+k],mul(f[i+j],x));
}
void AND(int *f,int x=1) {
for(int o=2,k=1; o<=n; o<<=1,k<<=1)
for(int i=0; i<n; i+=o)
rep(j,0,k-1) _add(f[i+j],mul(f[i+j+k],x));
}
void XOR(int *f,int x=1) {
for(int o=2,k=1; o<=n; o<<=1,k<<=1)
for(int i=0; i<n; i+=o)
rep(j,0,k-1)
_add(f[i+j],f[i+j+k]), f[i+j+k]=add(f[i+j],mod-add(f[i+j+k],f[i+j+k])), _mul(f[i+j],x), _mul(f[i+j+k],x);
}
调用方式:
OR(a), OR(b), calc(), OR(a,mod-1);
AND(a), AND(b), calc(), AND(a,mod-1);
XOR(a), XOR(b), calc(), XOR(a,ksm(2));
本文来自博客园,作者:liyixin,转载请注明原文链接:https://www.cnblogs.com/liyixin0514/p/18644476