FWT
来自 luogu.com.cn/article/y0unggsj 以及题目题解
要解决的问题
\(C_k=\sum_{i\oplus j=k} A_iB_j\),其中 \(\oplus\) 是一种位运算。
目标:\(A\rightarrow \text{FWT}(A)\),算出 \(\text{FWT}(A)\cdot \text{FWT}(B)\),满足其等于 \(\text{FWT}(C)\),再逆变换回来。
\(\text{FWT}\) 应是线性变换。所以 \(\text{FWT}(A+B)=\text{FWT}(A)+\text{FWT}(B)\),\(\text{FWT}(cA)=c\text{FWT}(A)\)。
设 \(c(i,j)\) 为变换系数,即 \(\text{FWT}(A)[i]=\sum_{j=0}^{n-1}c(i,j)A_j\)。
因为 \(\text{FWT}(A)\cdot \text{FWT}(B)=\text{FWT}(C)\),所以 \(\text{FWT}(A)[i]\cdot \text{FWT}(B)[i]=\text{FWT}(C)[i]\)。即
因为有 \(C_l=\sum_{j\oplus k=l}A_jB_k\),所以
右边从固定 \(l\) 变成枚举 \(j,k\),
所以,\(c(i,j)c(i,k)=c(i,j\oplus k)\)。
一位一位考虑,令 \(c(i,j)=c(i_0,j_0)c(i_1,j_1)\cdots c(i_k,j_k)\),那么只需要 \(c([0,1],[0,1])\) 知道就好了。
按位或
相当于按位取 \(\max\)。
有 \(c(i,j)c(i,j)=c(i,j|j)=c(i,j)\),所以 \(c(i,j)\in \{0,1\}\)。
\(c(x,y)c(x,z)=c(x,\max(y,z))\),如果 \(c(x,y)=1\),\(c(x,z)=0\),则 \(c(x,y)c(x,z)=0=c(x,z)\),所以 \(y<z\)。
所以一行中 \(1\) 在 \(0\) 前面。
为了让矩阵
有逆,所以矩阵满秩,所以不能有行是相同的。
那么每行 \(1\) 的个数正好就是 \(1,2,\cdots ,n\)。
所以得到 \(\begin{bmatrix}1 & 1 \\ 1 & 0\end{bmatrix}\) 或者 \(\begin{bmatrix}1 & 0 \\ 1 & 1\end{bmatrix}\)。
使用第二个矩阵,得到逆矩阵 \(\begin{bmatrix}1 & 0 \\ -1 & 1\end{bmatrix}\)。
按位与
相当于按位取 \(\min\)。
\(c(x,y)c(x,z)=c(x,\min(y,z))\),如果 \(c(x,y)=1\),\(c(x,z)=0\),则 \(c(x,y)c(x,z)=0=c(x,z)\),所以 \(y>z\)。
所以一行中 \(1\) 在 \(0\) 后面。
所以得到 \(\begin{bmatrix}0 & 1 \\ 1 & 1\end{bmatrix}\) 或者 \(\begin{bmatrix}1 & 1 \\ 0 & 1\end{bmatrix}\)。
使用第二个矩阵,得到逆矩阵 \(\begin{bmatrix}1 & -1 \\ 0 & 1\end{bmatrix}\)。
按位异或
有 \(c(0,0)c(0,y)=c(0,y\oplus 0)=c(0,y)\)。所以 \(c(0,0)=1\)。
有 \(c(1,1)c(1,1)=c(1,0)\),因为不能矩阵有一行都是 \(0\),所以 \(c(1,1),c(1,0)\neq 0\)。
有 \(c(1,0)c(1,1)=c(1,1)\),所以 \(c(1,0)=1\),所以 \(c(1,1)\in \{-1,1\}\)。
有 \(c(0,1)c(0,1)=c(0,0)\),所以 \(c(0,1)\in \{-1,1\}\)。
-
如果 \(c(0,1)=-1\),则 \(c(1,1)\neq c(0,1)\),所以 \(c(1,1)=1\)。
-
如果 \(c(0,1)=1\),则 \(c(1,1)=-1\)。
所以得到 \(\begin{bmatrix}1 & -1 \\ 1 & 1\end{bmatrix}\) 或者 \(\begin{bmatrix}1 & 1 \\ 1 & -1\end{bmatrix}\)。
使用第二个矩阵,得到逆矩阵 \(\begin{bmatrix}0.5 & 0.5 \\ 0.5 & -0.5\end{bmatrix}\)。
我们有 \(\text{FWT}(A)[i]=\sum_{j=0}^{n-1}c(i,j)A_j\)。
考虑优化,按位拆半:
设 \(i'\) 为 \(i\) 去掉二进制首位的数。则
这个时候两半遍历的 \(i',j'\) 是相等的,所以可以将规模减半。设 \(A_0\) 为首位为 \(0\) 的部分,\(A_1\) 为首位为 \(1\) 的部分,则有
-
\(i_0=0\),\(\text{FWT}(A)[i]=c(0,0)\text{FWT}(A_0)[i]+c(0,1)\text{FWT}(A_1)[i]\)。
-
\(i_0=1\),\(\text{FWT}(A)[i+n/2]=c(1,0)\text{FWT}(A_0)[i]+c(1,1)\text{FWT}(A_1)[i]\)。
其中上面的 \(i\in [0,n/2)\)。
设 \(n=2^m\),则复杂度 \(\mathcal{O}(m2^m)\)。
void OR(ll *f,ll ty=1){
for (int p=1; p<n; p*=2){
for (int i=0; i<n; i+=p*2){
for (int j=i; j<i+p; j++){
ll x=f[j],y=f[j+p];
f[j]=x;
f[j+p]=(y+x*ty%mod)%mod;
}
}
}
}
void AND(ll *f,ll ty=1){
for (int p=1; p<n; p*=2){
for (int i=0; i<n; i+=p*2){
for (int j=i; j<i+p; j++){
ll x=f[j],y=f[j+p];
f[j]=(x+y*ty%mod)%mod;
f[j+p]=y;
}
}
}
}
void XOR(ll *f,ll ty=1){
for (int p=1; p<n; p*=2){
for (int i=0; i<n; i+=p*2){
for (int j=i; j<i+p; j++){
ll x=f[j],y=f[j+p];
f[j]=(x+y)*ty%mod;
f[j+p]=(x-y+mod)*ty%mod;
}
}
}
}
CF 1119 H
第一个想法是令 \(F_i[a_i]=x,F_i[b_i]=y,F_i[c_i]=z\),然后计算一个 \(\prod F_i\)。但是这个太慢了。
发现 \(F_i\) 只有三个非零位置,所以可以得到 \(\text{FWT}(F_k)[i]=c(i,a_k)x+c(i,b_k)y+c(i,c_k)z\)。
根据上面按位异或卷积的推导,把每一位的 \(c(\_,\_)\) 乘起来,得到 \(c(i,j)=(-1)^{|i\cap j|}\)。
那么 \(\text{FWT}(F_k)[i]=(-1)^{|i\cap a_k|}x+(-1)^{|i\cap b_k|}y+(-1)^{|i\cap c_k|}z\)。那么 \(\text{IFWT}(\prod \text{FWT}(i))\) 就是答案。
一共有 \(8\) 种 \(\{-1,1\}^3\) 的情况,为了简化可以考虑 $\text{FWT[i]}\gets \text{FWT}[i\oplus a_1\oplus a_2\cdots \oplus a_k] $,因为异或的自反性,所以 \(\{a_i,b_i,c_i\}\) 可以变成 \(\{0,b_i\oplus a_i,c_i\oplus a_i\}\)。那么只有 \(4\) 种了。(*)
如果我们知道 \(x+y+z,x+y-z,x-y+z,x-y-z\) 分别的方案数 \(c_1,c_2,c_3,c_4\)(注意是对于每一个 \(i\) 而言),就可以通过快速幂求出答案。直接很难求,所以列一些方程,找一些关系(**)
- \(c_1+c_2+c_3+c_4=n\)。
- 令 \(x=0,y=1,z=0\),那么 \(\text{FWT}(F_k)[i]=(-1)^{|i\cap b_k|}\)。考虑贡献,有 \(\sum_{k=1}^n \text{FWT}(F_k)[i]=(-1)^{|i\cap b_k|}=c_1+c_2-c_3-c_4\)。因为 \(\text{FWT}\) 是线性变换,所以 \(\sum_{k=1}^n \text{FWT}(F_k)=\text{FWT}(\sum_{k=1}^n F_k)\),也就是 \(F'[k]=\sum_{i=1}^n [b_i=k]\) 的 \(\text{FWT}\)。
- 同理求出 \(c_1-c_2+c_3-c_4\),\(c_1-c_2-c_3+c_4\)(这个令 \(F_k[b_k\oplus c_k]=1\))。
解一个方程就好了。
(*)理论上 \(8\) 种的也可以,但是小巧思简化思维代码难度。
(**)很好的方法,如果无从下手就尝试找到关系式。
CF 2194 F2
F1 提示我们先从暴力开始。
很显然,设 \(f_{u,x}\) 为子树 \(u\),被切断的异或和是 \(x\) 的方案数,那么初始 \(f_{u,0}=1\)。发现 \(x\) 其实是 \(b\) 中的线性组合,所以只用考虑 \(b\) 构成的线性基中的数,设 \(k'\) 为线性基大小,那么 \(x\) 可以用一个 \(k'\) 位二进制数表示。
转移考虑合并子树和切断自己。第一种可以异或卷积,第二种考虑子树异或和 \(s_u\),那么 \(f_{u,s_u}\gets f_{u,s_u}+\sum f_{u,s_u\oplus b_i}\)。
现在的复杂度是 \(\mathcal{O}(n4^{k'})\) 的。考虑优化。
考虑维护 \(\text{FWT}(f)\)。那么初始化 \(f_{u,0}=1\) 相当于 \(\text{FWT}(f_u)=[1]\times 2^{k'}\)。异或卷积就是点乘。
现在要计算 \(\sum f_{u,s_u\oplus b_i}\)。这里 \(s,b\) 已经是二进制数表示了。把这个看成 \(\sum f_{u,s_u\oplus b_i}\times 1\),那么构造 \(g\),使得 \(g_{b_i}=1\),其他等于 \(0\)。那么可以看成 \(\sum f_{u,s_u\oplus b_i}\times g_{b_i}=\sum_{i\oplus j=s_u}f_ig_j\)。可以求 \(\text{FWT}(g)\),然后算出 \(\text{FWT}(f\times g)=\text{FWT}(f)\times \text{FWT}(g)\)。那么 \(\text{IFWT}(f\times g)[s_u]\) 即为所求。(*)
注意到这里单点求值,直接可以 \(\mathcal{O}(2^{k'})\) 算出,即为
将其加到 \(f_{u,s_u}\) 上,相当于 \(\text{FWT}(f)[i]\gets \text{FWT}(f)[i]+(-1)^{|i\cap s_u|} val\)。
(*)这种看成异或卷积形式,非常厉害。

浙公网安备 33010602011771号