FWT学习笔记
FWT
FWT 即位运算卷积,用来快速计算形如 \(\sum\limits_{i\oplus j=k}f_ig_j\),其中 \(\oplus\) 表示某种位运算。
设 FWT(A) 是幂级数 A经过 \(\rm FWT\) 变换之后得到的幂级数。
我们需要令其满足 : \(A*B=C \Longleftrightarrow FWT(A)·FWT(B)=FWT(C)\)(点积)。
\(\rm FFT\) 是一个线性变换,我们也希望 \(\rm FWT\) 变换是线性的。
我们还不知道怎么变换,于是设 \(c(i,j)\) 为变换系数,即 \(A[j]\) 对 $FWT(A)[i] $ 的贡献系数。
则 \(FWT(A)[i]=\sum\limits_{j=0}^{n-1}c(i,j)A_j\)
由\(FWT(A)*FWT(B)=FWT(C)\),得到:
\(FWT(A)[i]FWT(B)[i]=FWT(C)[i]\)
\(\sum\limits_{j=0}^{n-1}c(i,j)A[j]\sum\limits_{k=0}^{n-1}c(i,k)B[k]=\sum\limits_{p=0}^{n-1}c(i,p)C[p]\)
\(\sum\limits_{j=0}^{n-1}\sum\limits_{k=0}^{n-1}c(i,j)c(i,k)A[j]B[k]=\sum\limits_{p=0}^{n-1}c(i,p)C[p]\)
根据 \(A*B=C\) 得到:
\(C[p]=\sum\limits_{t1\oplus t2=p}A[t1]B[t2]\)
\(\sum\limits_{p=0}^{n-1}c(i,p)C[p]=\sum\limits_{p=0}^{n-1}c(i,p)\sum\limits_{t1\oplus t2=p}A[t1]B[t2]\)
\(\sum\limits_{j=0}^{n-1}\sum\limits_{k=0}^{n-1}c(i,j)c(i,k)A[j]B[k]=\sum\limits_{p=0}^{n-1}c(i,p)\sum\limits_{t1\oplus t2=p}A[t1]B[t2]\)
\(\sum\limits_{j=0}^{n-1}\sum\limits_{k=0}^{n-1}c(i,j)c(i,k)A[j]B[k]=\sum\limits_{p=0}^{n-1}\sum\limits_{t1\oplus t2=p}A[t1]B[t2]c(i,t1\oplus t2)=\sum\limits_{t1=0}^{n-1}\sum\limits_{t2=0}^{n-1}A[t1]B[t2]c(i,t1\oplus t2)\)
对比左右两边,我们发现只要满足 \(c(i,k)c(i,k)=c(i,j\oplus k)\) 就好了
现在,假设有了符合要求的 \(c\),如何优化FWT呢?
我们把 \(FWT(A)[i]=\sum\limits_{j=0}^{n-1}c(i,j)A[j]\) 按位折半,有
\(=\sum\limits_{j=0}^{\frac{n}{2}-1}c(i,j)A[j]+\sum\limits_{j=\frac{n}{2}}^{n-1}c(i,j)A[j]\) 设 \(i'\)
为 \(i\) 去掉最高位的数字,那么有
\(\sum\limits_{j=0}^{\frac{n}{2}-1}c(i_0,j_0)c(i',j')A[j]+\sum\limits_{j=\frac{n}{2}}^{n-1}c(i_0,j_0)c(i',j')A[j]\)
\(=c(i_0,0)\sum\limits_{j=0}^{\frac{n}{2}-1}c(i',j')A[j]+c(i_0,1)\sum\limits_{j=\frac{n}{2}}^{n-1}c(i,j)A[j]\)
再设 \(A_0\) 下标首位为 \(0\) 的部分,如果 \(i_0=0\),则有:
\(FWT(A)[i]=c(0,0)FWT(A_0)[i]+c(0,1)FWT(A_1)[i]\;\;\;(i\in[0,\frac{n}{2}))\)
如果 \(i_0=1\),则有
\(FWT(A)[i+\frac{n}{2}]=c(1,0)FWT(A_0)[i]+c(1,1)FWT(A_1)[i]\;\;\;(i\in[0,\frac{n}{2}))\)
这就变成了一个规模为 \(\frac{n}{2}\) 的子问题。
因此关键就是 c 矩阵。
Or卷积
\(c=\begin{bmatrix}1&0\\1&1\end{bmatrix},c^{-1}=\begin{bmatrix}1&0\\-1&1\end{bmatrix}\)
即:
And卷积
\(c=\begin{bmatrix}1&1\\0&1\end{bmatrix},c^{-1}=\begin{bmatrix}1&-1\\0&1\end{bmatrix}\)
即:
\(FWT(A)[i]=FWT(A_0)[i]+FWT(A_1)[i],FWT(A)[i+\frac{n}{2}]=FWT(A_1)[i]\)
\(IFWT(A)[i]=IFWT(A_0)[i]-IFWT(A_1)[i],IFWT(A)[i+\frac{n}{2}]=IFWT(A_1)[i]\)
Xor卷积
\(c=\begin{bmatrix}1&1\\1&-1\end{bmatrix},c^{-1}=\begin{bmatrix}0.5&0.5\\0.5&-0.5\end{bmatrix}\)
即:
\(FWT(A)[i]=FWT(A_0)[i]+FWT(A_1)[i],FWT(A)[i+\frac{n}{2}]=FWT(A_0)[i]-FWT(A_1)[i]\)
\(IFWT(A)[i]=0.5IFWT(A_0)[i]+0.5IFWT(A_1)[i],IFWT(A)[i+\frac{n}{2}]=0.5IFWT(A_0)[i]-0.5IFWT(A_0)[i]\)
CF850E Random Elections
题意:有3个候选人和 \(n\) 个投票的人,每个人对三个人的支持度排序,候选人之间两两比赛,每次比赛时,第 \(i\) 个人对哪个人更支持哪个就是1,否则是0,有函数 \(f\),会把这 \(n\) 个01变成0或1,1就是赢,否则是输,求有多少种方案使得有个人赢了两场。
思路:首先,哪个人赢了两场是不重要的,于是可以钦定 \(a\) 赢了两场,最后再乘3。a和 \(b,c\) 在第 \(i\) 个人处有 4 种情况,其中 \(b_i=c_i\) 的情况有两种,于是可以枚举 \(b_i!=c_i\) 求方案数,再乘上 \(2^{n-ppc(S)}\)。发现剩下的情况就是先令 \(g_k=\sum\limits_{i\oplus j=k}f_if_j\),然后有 \(ans=\sum\limits_{i=0}^{2^n}g_i2^{n-ppc(i)}\),可以直接用 FWT。复杂度 \(O(n2^n)\)。
P3175 [HAOI2015] 按位或
题意:刚开始你有一个数字 \(0\),每一秒钟你会随机选择一个 \([0,2^n-1]\) 的数字,与你手上的数字进行或(C++,C 的 |
,pascal 的 or
)操作。选择数字 \(i\) 的概率是 \(p_i\)。保证 \(0\leq p_i \leq 1\),\(\sum p_i=1\) 。问期望多少秒后,你手上的数字变成 \(2^n-1\)。
思路:首先用 \(\text{min-max}\) 容斥,设 \(Emax(S)\) 为遍历 \(S\) 中所有元素的最晚时间,那么 \(Emax(S)=\sum\limits_{T\subseteq S}(-1)^{|T|+1}Emin(T)\)。
考虑怎么求 \(Emin(S)\)。根据期望的定义,有 \(Emin(S)=\sum\limits_{i=1}^{\infty}i[Pmin(S)=i]\),而 \(Pmin(S)=(\sum\limits_{T\cap S=\varnothing}P(T))^{i-1}(1-\sum\limits_{T\cap S=\varnothing}P(T))\),于是有 \(Emin(S)=\dfrac{1}{1-\sum\limits_{T\cap S=\varnothing}P(T)}=\dfrac{1}{1-\sum\limits_{T\subseteq\complement_US}P(T)}\)。
现在的问题就是求子集和。可以直接用 FWT 解决。
Binary Table
题意:有一个 \(n\) 行 \(m\) 列的表格,每个元素都是 \(0/1\) ,每次操作可以选择一行或一列,把 \(0/1\) 翻转,即把 \(0\) 换为 \(1\) ,把 \(1\) 换为 \(0\) 。请问经过若干次操作后,表格中最少有多少个 \(1\) 。
思路:考虑枚举翻转了哪些行,记 \(F(S)\) 表示 \(S\) 翻转后最少的 1 个数,那么 \(S\) 的答案就是 \(\sum F(S\oplus T_i)\)。
考虑枚举 \(Y_i=S\oplus T_i\),那么就是 \(\sum\limits_{i}\sum\limits_{Y}[Y=T_i\oplus S]F(Y)\),记 \(cnt(Y)\) 表示有多少列是 \(Y\),那么就是 \(\sum\limits_{T}\sum\limits_{Y}[Y=S\oplus T]F(Y)cnt(T)=\sum\limits_{T}\sum\limits_{Y}[T\oplus Y=S]F(Y)cnt(T)\),发现这就是异或卷积,于是可以直接 FWT。
子集卷积
子集卷积是指对于给定序列 \(a,b\),求出 \(c_i=\sum\limits_{j|i=k,j\&k=0}a_j\times b_k\)。
对于第一个限制可以直接 OR 卷积,但是现在有了第二个限制,就不那么好做了。
但是因为对于 \(i\&j=0\),有 \(popcount(i)+popcount(j)=popcount(i|j)\),于是我们可以记
把 f 和 g 用 OR 卷积卷起来得到 h,然后 \(h_{popcount(i),i}\) 就是答案。
CF1034E Little C Loves 3 III
题意:有两个序列 \(a,b\),要求对每个 \(i\) 求出 \(\sum\limits_{j|k=i,j\&k=0}a_jb_k\),答案对 4 取模。
思路:容易想到子集卷积,复杂度是 \(O(n\log^2n)\)。
考虑能否用上对 4 取模的条件。
记 \(ppc(x)=popcount(x)\),那么我们令 \(a_i\leftarrow a_i\times 4^{ppc(i)},b_i\leftarrow b_i\times 4^{ppc(i)}\),把 \(a,b\) 用 OR 卷积卷起来得到 \(c\),再令 \(c_i\leftarrow \dfrac{c_i}{4^{ppc(i)}}\) 就是答案。
为什么这样做是对的呢?假设 \(i\&j=0\),那么 \(\dfrac{4^{ppc(i)}\times 4^{ppc(j)}}{4^{ppc(i|j)}}=1\),而当 \(i\&j\ne 0\) 时,上式就是 4 的正整数次幂,再对 4 取模就没有贡献了,因此这样做是对的。
复杂度 \(O(n\log n)\)。