《小学生都能看懂的快速沃尔什变换从入门到升天教程》(FWT / FMT / FMI)(最最严谨清晰的证明!零基础也能得学会!)

整理的算法模板合集: ACM模板

点我看算法全家桶系列!!!

实际上是一个全新的精炼模板整合计划


前置知识:FFT

开始的开始,我们先来复习一下卷积的相关概念(注:0x00 卷积的部分内容(0x02、0x03、0x04)摘自 @wangrx,他写的太好了 %%%,略作修改完善,侵删)之后本文中所有的符号也都参照他的形式书写。以及本文中所有的多项式的系数 n n n 均为 2 2 2 的整数幂的形式(学过 FFT 的都懂hhh不然就没法分治了)

自认为本文是最为清晰完整的 FWT 讲解博客,含有全套完整清晰的证明,相信小学生都能看懂 ~

前排规定本文所用符号:

多项式 / 序列卷积 ⊗ \otimes

多项式 / 序列对应系数相乘 / 普通的乘法 × \times ×

多项式 / 序列第 k k k 项系数 ( f ) k (f)_k (f)k ( f ⊗ g ) k (f\otimes g)_k (fg)k ( A ) [ k ] (A)[k] (A)[k]

多项式 / 序列加法 ⊕ \oplus

多项式 / 序列减法 ⊖ \ominus

多项式 / 序列 or \text {or} or 卷积( |,或) ⊗ or \otimes_{\text{or}} or

多项式 / 序列 and \text {and} and 卷积( &,或) ⊗ and \otimes_{\text{and}} and

多项式 / 序列 xor \text {xor} xor 卷积( ^,或) ⊗ xor \otimes_{\text{xor}} xor

0x00 卷积

0x01 多项式

我们知道对于一个普通的多项式可以表示为系数表示 f ( x ) = a 0 x 0 + a 1 x 1 + ⋅ ⋅ ⋅ + a n − 1 x n − 1 f(x)=a_0x^0+a_1x^1+···+a_{n-1}x^{n-1} f(x)=a0x0+a1x1++an1xn1

规定 f = a 0 x 0 + a 1 x 1 + ⋅ ⋅ ⋅ + a n − 1 x n − 1 f=a_0x^0+a_1x^1+···+a_{n-1}x^{n-1} f=a0x0+a1x1++an1xn1 g = b 0 x 0 + b 1 x 1 + ⋅ ⋅ ⋅ + b n − 1 x n − 1 g=b_0x^0+b_1x^1+···+b_{n-1}x^{n-1} g=b0x0+b1x1++bn1xn1

则可将多项式的系数表示简化为: f = ( a 0 , a 1 , a 2 ⋅ ⋅ ⋅ a n − 1 ) f=(a_0,a_1,a_2···a_{n-1}) f=(a0,a1,a2an1) g = ( b 0 , b 1 , b 2 ⋅ ⋅ ⋅ b n − 1 ) g=(b_0,b_1,b_2···b_{n-1}) g=(b0,b1,b2bn1)


定义多项式加减法 ⊕ , ⊖ \oplus,\ominus ,
H = f ⊕ g = ( a 0 , a 1 , a 2 ⋅ ⋅ ⋅ a n − 1 ) ⊕ ( b 0 , b 1 , b 2 ⋅ ⋅ ⋅ b n − 1 ) = ( a 0 + b 0 , a 1 + b 1 , a 2 + b 2 ⋅ ⋅ ⋅ a n − 1 + b n − 1 ) \begin{aligned} H&=f\oplus g\\& =(a_0,a_1,a_2⋅⋅⋅a_{n−1})\oplus (b_0,b_1,b_2⋅⋅⋅b_{n−1})\\&=(a_0+b_0,a_1+b_1,a_2+b_2⋅⋅⋅a_{n−1}+b_{n−1}) \end{aligned} H=fg=(a0,a1,a2an1)(b0,b1,b2bn1)=(a0+b0,a1+b1,a2+b2an1+bn1)

H = f ⊖ g = ( a 0 , a 1 , a 2 ⋅ ⋅ ⋅ a n − 1 ) ⊕ ( b 0 , b 1 , b 2 ⋅ ⋅ ⋅ b n − 1 ) = ( a 0 − b 0 , a 1 − b 1 , a 2 − b 2 ⋅ ⋅ ⋅ a n − 1 − b n − 1 ) \begin{aligned} H&=f\ominus g\\& =(a_0,a_1,a_2⋅⋅⋅a_{n−1})\oplus (b_0,b_1,b_2⋅⋅⋅b_{n−1})\\&=(a_0-b_0,a_1-b_1,a_2-b_2⋅⋅⋅a_{n−1}-b_{n−1}) \end{aligned} H=fg=(a0,a1,a2an1)(b0,b1,b2bn1)=(a0b0,a1b1,a2b2an1bn1)

其中多项式加减的第 k k k 项系数:

( f ⊕ g ) k = a k f k + b k g k (f\oplus g)_k=a_kf_k+b_kg_k (fg)k=akfk+bkgk

( f ⊖ g ) k = a k f k − b k g k (f\ominus g)_k=a_kf_k-b_kg_k (fg)k=akfkbkgk


定义多项式对应系数相乘一定注意这里不是卷积 ⊗ \otimes
H = f × g = ( a 0 , a 1 , a 2 ⋅ ⋅ ⋅ a n − 1 ) × ( b 0 , b 1 , b 2 ⋅ ⋅ ⋅ b n − 1 ) = ( a 0 × b 0 , a 1 × b 1 , a 2 × b 2 ⋅ ⋅ ⋅ a n − 1 × b n − 1 ) \begin{aligned} H&=f\times g\\& =(a_0,a_1,a_2⋅⋅⋅a_{n−1})\times (b_0,b_1,b_2⋅⋅⋅b_{n−1})\\&=(a_0\times b_0,a_1\times b_1,a_2\times b_2⋅⋅⋅a_{n−1}\times b_{n−1}) \end{aligned} H=f×g=(a0,a1,a2an1)×(b0,b1,b2bn1)=(a0×b0,a1×b1,a2×b2an1×bn1)

其中多项式对应系数相乘的第 k k k 项系数:

( f ⊗ g ) k = a k f k × b k g k (f\otimes g)_k=a_kf_k\times b_kg_k (fg)k=akfk×bkgk


0x02 卷积的定义

对于一个序列,将其中元素一一映射到一个多项式函数的系数上, 这个多项式函数便叫做该序列的生成函数

形式化地讲,对于序列 f 0 , f 1 , ⋯   , f n − 1 f_0,f_1,\cdots,f_{n-1} f0,f1,,fn1 F ( x ) = ∑ k = 0 n − 1 f k x k F(x)=\displaystyle\sum_{k=0}^{n-1}f_kx^k F(x)=k=0n1fkxk 为其生成函数。

卷积即为生成函数的乘积在对应序列的变换上的的抽象,“卷”即为其作用效果,“积”即为其本质。

对于序列 f , g f,g f,g ,其卷积序列 f ⊗ g f\otimes g fg 满足 ( f ⊗ g ) k = ∑ i = 0 k f i × g k − i = ∑ i , j i + j = k f i × g j (f\otimes g)_k=\displaystyle\sum\limits_{i=0}^kf_i\times g_{k-i}=\sum\limits_{i,j}^{i+j=k}f_i\times g_j (fg)k=i=0kfi×gki=i,ji+j=kfi×gj

对于多项式 f , g f,g f,g,其多项式的卷积为: f ⊗ g = ∑ k = 0 n ( ∑ i , j i + j = k a i × b j ) x k f\otimes g=\sum\limits_{k=0}^{n}(\sum\limits_{i,j}^{i+j=k}a_i\times b_j)x^k fg=k=0n(i,ji+j=kai×bj)xk

而我们所熟知的 FFT 计算的是循环卷积,也即 ( f ⊗ g ) k = ∑ i + j ≡ k ( m o d n ) f i × g j (f\otimes g)_k=\displaystyle\sum_{i+j\equiv k\pmod n}f_i\times g_j (fg)k=i+jk(modn)fi×gj n n n 为序列长度。

0x03 卷积的基本性质

这里的卷积均为序列的卷积,因此证明时我们使用数学归纳法,即证明第 k k k 项成立,则整个序列均成立。由于多项式实际上就是序列的生成函数,所以性质同样成立。

  • f ⊗ g = g ⊗ f f\otimes g=g\otimes f fg=gf(交换律)

    我们使用定义 ( f ⊗ g ) k = ∑ i + j = k f i × g j (f\otimes g)_k=\displaystyle\sum_{i+j=k}f_i\times g_j (fg)k=i+j=kfi×gj ,以及乘法交换律 a × b = b × a a\times b=b\times a a×b=b×a 即可证明,因为 i + j = k i+j=k i+j=k i i i j j j 是一一对应的。

  • ( f ⊗ g ) ⊗ h = f ⊗ ( g ⊗ h ) (f\otimes g)\otimes h=f\otimes(g \otimes h) (fg)h=f(gh) (结合律)
    证明:
    [ f ⊗ ( g ⊗ h ) ] n = ∑ i = 0 n f n − i × ( g ⊗ h ) i = ∑ i = 0 n f n − i ∑ j = 0 i g j h i − j = ∑ i = 0 n ∑ j = 0 i f n − i g j h i − j = ∑ i + j + k = n f i g j h k \begin{aligned} {[f\otimes(g\otimes h)]_n} & =\displaystyle\sum_{i=0}^nf_{n-i}\times(g\otimes h)_i & \\& =\sum_{i=0}^nf_{n-i}\sum_{j=0}^ig_jh_{i-j}\\& =\sum_{i=0}^n\sum_{j=0}^if_{n-i}g_jh_{i-j}\\& =\sum_{i+j+k=n}f_ig_jh_k\end{aligned} [f(gh)]n=i=0nfni×(gh)i=i=0nfnij=0igjhij=i=0nj=0ifnigjhij=i+j+k=nfigjhk

交换顺序后反向推导即可得证。

  • ( f ⊕ g ) ⊗ h = ( f ⊗ h ) ⊕ ( g ⊗ h ) (f\oplus g)\otimes h=(f\otimes h)\oplus(g\otimes h) (fg)h=(fh)(gh) (分配律)
    其中 ( f ⊕ g ) k = a f k + b g k (f\oplus g)_k=af_k+bg_k (fg)k=afk+bgk ,即序列 f , g f,g f,g 的加法, a , b a,b a,b 为常数。

证明:
[ ( f ⊕ g ) ⊗ h ] k = ∑ i = 0 k ( f ⊕ g ) i h k − i = ∑ i = 0 k ( a f i + b g i ) h k − i = ∑ i = 0 k ( a f i h k − i + b g i h k − i ) = a ∑ i = 0 k f i h k − i + b ∑ i = 0 k g i h k − i = a ( f ⊗ h ) k + b ( g ⊗ h ) k = [ ( f ⊗ h ) ⊕ ( g ⊗ h ) ] k \begin{aligned} {[(f\oplus g)\otimes h]_k} &=\displaystyle\sum_{i=0}^k(f\oplus g)_ih_{k-i}\\ & =\sum_{i=0}^k (af_i+bg_i)h_{k-i} \\ &=\sum_{i=0}^k(af_ih_{k-i}+bg_ih_{k-i})\\ &=a\sum_{i=0}^kf_ih_{k-i}+b\sum_{i=0}^kg_ih_{k-i}\\&=a(f\otimes h)_k+b(g\otimes h)_k=[(f\otimes h)\oplus(g\otimes h)]_k \end{aligned} [(fg)h]k=i=0k(fg)ihki=i=0k(afi+bgi)hki=i=0k(afihki+bgihki)=ai=0kfihki+bi=0kgihki=a(fh)k+b(gh)k=[(fh)(gh)]k

0x04 位运算卷积定义及其性质

一般的卷积满足 i + j = k i+j=k i+j=k ,又称为加法卷积。

类似的,对于序列 f = { f 0 , f 1 , ⋯   , f 2 n − 1 } , g = { g 0 , g 1 , ⋯   , g 2 n − 1 } f=\{f_0,f_1,\cdots,f_{2^n-1}\},g=\{g_0,g_1,\cdots,g_{2^n-1}\} f={f0,f1,,f2n1},g={g0,g1,,g2n1}
可以定义位运算卷积 ( f ⊗ ⊙ g ) k = ∑ i ⊙ j = k f i × g j \displaystyle(f\otimes_\odot g)_k=\sum_{i\odot j=k}f_i\times g_j (fg)k=ij=kfi×gj ,其中 ⊙ = and , or , xor \odot=\text{and},\text{or},\text{xor} =and,or,xor
还有 max ⁡ \max max 卷积,这里不再拓展, 读者自行查找相关资料,现在着重讨论 ⊗ xor \otimes_\text{xor} xor

  • f ⊗ xor g = g ⊗ xor \displaystyle f\otimes_\text{xor} g=g\otimes_\text{xor} fxorg=gxor (交换律)
    由于 a xor ⁡ b = b xor ⁡ a\operatorname{xor}b=b\operatorname{xor} axorb=bxor ,根据定义显然成立。
    and ⁡ , or ⁡ a n d , o r \operatorname{and},\operatorname{or}and,or and,orand,or 同样满足此性质,原因同上。
  • ( f ⊗ xor g ) ⊗ xor h = f ⊗ xor ( g ⊗ xor h ) (f\otimes_\text{xor} g)\otimes_\text{xor} h=f\otimes_\text{xor}(g \otimes_\text{xor} h) (fxorg)xorh=fxor(gxorh) (结合律)
    证明: 根据定义,有 ( f ⊗ xor g ) k = ∑ i xor ⁡ j = k f i × g j = ∑ i = 0 2 n − 1 f i × g k xor ⁡ i (f\otimes_\text{xor} g)_k=\displaystyle\sum_{i\operatorname{xor}j=k}f_i\times g_j=\sum\limits_{i=0}^{2^n-1}f_i\times g_{k\operatorname{xor}i} (fxorg)k=ixorj=kfi×gj=i=02n1fi×gkxori ,则

[ f ⊗ xor ( g ⊗ xor h ) ] m = ∑ i = 0 2 n − 1 f m xor ⁡ i × ( g ⊗ xor h ) i = ∑ i = 0 2 n − 1 f m xor ⁡ i ∑ j = 0 2 n − 1 g j h i xor ⁡ j = ∑ i = 0 2 n − 1 ∑ j = 0 2 n − 1 f m xor ⁡ i g j h i xor ⁡ j = ∑ i xor ⁡ j xor ⁡ k = m f i g j h k \begin{aligned} {[f\otimes_\text{xor}(g\otimes_\text{xor}h)]_m} & =\sum_{i=0}^{2^n-1}f_{m\operatorname{xor}i}\times(g\otimes_\text{xor}h)_i \\&=\sum_{i=0}^{2^n-1}f_{m\operatorname{xor}i}\sum_{j=0}^{2^n-1}g_jh_{i\operatorname{xor}j}\\&=\sum_{i=0}^{2^n-1}\sum_{j=0}^{2^n-1}f_{m\operatorname{xor}i}g_jh_{i\operatorname{xor}j}\\& =\sum_{i\operatorname{xor}j\operatorname{xor}k=m}f_ig_jh_k\end{aligned} [fxor(gxorh)]m=i=02n1fmxori×(gxorh)i=i=02n1fmxorij=02n1gjhixorj=i=02n1j=02n1fmxorigjhixorj=ixorjxork=mfigjhk

交换顺序后反向推导即可得证。
or ⁡ , and ⁡ \operatorname{or},\operatorname{and} or,and 没有对应的逆运算,因此证明相对复杂,这里不给出证明。

  • ( f ⊕ g ) ⊗ xor h = ( f ⊗ xor h ) ⊕ ( g ⊗ xor h ) (f\oplus g)\otimes_\text{xor} h=(f\otimes_\text{xor} h)\oplus(g\otimes_\text{xor} h) (fg)xorh=(fxorh)(gxorh) (分配律)
    证明同加法卷积, and ⁡ , or ⁡ \operatorname{and},\operatorname{or} and,or 同理。

0x10 FWT(快速沃尔什变换)

复习完上述基本概念以后,我们进入今天的正题,快速沃尔什变换(FWT)。

我们知道 FFT 是用来在 O ( n l o g n ) \mathcal O(nlogn) O(nlogn) 的时间复杂度下利用分治求解普通序列 / 多项式的卷积:

对于序列 f , g f,g f,g ,其卷积序列 f ⊗ g f\otimes g fg 满足对于 f ⊗ g f\otimes g fg 的第 k k k 项: ( f ⊗ g ) k = ∑ i = 0 k f i × g k − i = ∑ i , j i + j = k f i × g j (f\otimes g)_k=\displaystyle\sum\limits_{i=0}^kf_i\times g_{k-i}=\sum\limits_{i,j}^{i+j=k}f_i\times g_j (fg)k=i=0kfi×gki=i,ji+j=kfi×gj

对于多项式 f , g f,g f,g,其多项式的卷积为: f ⊗ g = ∑ k = 0 n ( ∑ i , j i + j = k a i × b j ) x k \displaystyle f\otimes g=\sum\limits_{k=0}^{n}(\sum\limits_{i,j}^{i+j=k}a_i\times b_j)x^k fg=k=0n(i,ji+j=kai×bj)xk

上面定义了位运算卷积: ( f ⊗ ⊙ g ) k = ∑ i ⊙ j = k f i × g j \displaystyle(f\otimes_\odot g)_k=\sum_{i\odot j=k}f_i\times g_j (fg)k=ij=kfi×gj ,其中 ⊙ = and , or , xor \odot=\text{and},\text{or},\text{xor} =and,or,xor ,并讲解了一系列相关性质,那么我们如何求得位运算卷积呢?我们模仿 FFT 给出一种类似的求解算法:快速沃尔什变换(FWT)。

严格来讲,FWT 仅为 xor \text {xor} xor 卷积,FMT 为 and \text{and} and or \text{or} or 卷积,这里放到一块统称为 FWT。(Qwq)

首先我们先来回忆一下FFT是如何求解多项式卷积呢?

我们将两个 ( n − 1 ) (n - 1) (n1) 次多项式 A ( x )   =   ∑ i = 0 n − 1 a i x i \displaystyle A(x)~=~\sum\limits_{i = 0}^{n - 1} a_i x^i A(x) = i=0n1aixi B ( x )   =   ∑ i = 0 n − 1 b i x i \displaystyle B(x)~=~\sum\limits_{i = 0}^{n - 1} b_i x^i B(x) = i=0n1bixi 的系数数列 { a i } \{a_i\} {ai},对其进行离散傅里叶变换(DFT)得到的两个点值表示 { A d i } \{Ad_i\} {Adi} { B d i } \{Bd_i\} {Bdi},其中 A d k   =   ∑ i = 0 n − 1 a i × ω n i k \displaystyle Ad_k~=~\sum\limits_{i = 0}^{n - 1} a_i \times \omega_n^{ik} Adk = i=0n1ai×ωnik,我们使用 FFT 在 O ( n l o g n ) \mathcal O(nlogn) O(nlogn) 的时间复杂度下完成这一操作。

之后在 O ( n ) \mathcal O(n) O(n) 的时间复杂度下完成两个点值表示的多项式的乘积 C i = A d i × B d i C_i=Ad_i\times Bd_i Ci=Adi×Bdi

最后利用结论 a k   =   1 n ∑ i = 0 n − 1 d i ω n − k i \displaystyle a_k~=~\frac{1}{n} \sum_{i = 0}^{n - 1} d_i \omega_n^{-ki} ak = n1i=0n1diωnki ,通过逆离散傅里叶变换(IDFT)还原系数数列 { c i } \{c_i\} {ci} 得到答案,同样使用 FFT 在 O ( n l o g n ) \mathcal O(nlogn) O(nlogn) 的时间复杂度下完成这一操作。

我们借鉴多项式乘法即普通卷积的实现 FFT 得出类似的思路 FWT:

我们先根据多项式的系数表示,求出多项式的另一种表示:点值表示 F W T ( A ) FWT(A) FWT(A) ,然后在 O ( n ) \mathcal O(n) O(n) 下将对应的位置乘起来,最后复原即可。

即答案 F W T ( C ) = F W T ( A ) × F W T ( B ) \displaystyle FWT(C)=FWT(A)\times FWT(B) FWT(C)=FWT(A)×FWT(B)(其中 × \times ×多项式 / 序列 对应位置相乘

看上去思路没有什么问题。我们考虑证明。

由于位运算卷积分为三种 ⊙ = and , or , xor \odot=\text{and},\text{or},\text{xor} =and,or,xor ,所以我们分开讨论。

0x11 或( or \text{or} or)卷积

或( or \text{or} or| ) 按位或运算符, |1110

或卷积: ( f ⊗ or g ) k = ∑ i ∣ j = k f i × g j \displaystyle(f\otimes_{\text{or}} g)_k=\sum_{i| j=k}f_i\times g_j (forg)k=ij=kfi×gj

对于序列 A , B , C A,B,C A,B,C A = { a 0 , a 1 ⋯   , a n } A=\{a_0,a_1\cdots,a_{n}\} A={a0,a1,an} B = { b 0 , b 1 , ⋯   , b n } B=\{b_0,b_1,\cdots,b_n\} B={b0,b1,,bn} C = { c 0 , c 1 , ⋯ c n } C=\{c_0,c_1,\cdots c_n\} C={c0,c1,cn} ,我们令 C C C 为或卷积的结果。

我们想要求的式子为 F W T ( C ) = F W T ( A ) × F W T ( B ) FWT(C)=FWT(A)\times FWT(B) FWT(C)=FWT(A)×FWT(B) ,即: c k = ∑ i ∣ j = k a i b j \displaystyle c_{k}=\sum_{i \mid j=k} a_{i} b_{j} ck=ij=kaibj

显然有 i ∣ k = k , j ∣ k = k → ( i ∣ j ) ∣ k = k i|k = k, j|k=k \to (i|j)|k=k ik=k,jk=k(ij)k=k

因此我们构造快速沃尔什变换 F W T FWT FWT F W T ( A ) [ k ] = ∑ i ∣ k = k a i \displaystyle FWT(A)[k]=\sum_{i|k=k}a_i FWT(A)[k]=ik=kai
F W T ( A ) × F W T ( B ) = ( ∑ i ∣ k = k a i ) ( ∑ j ∣ k = k b j ) = ∑ i ∣ k = k ,   j ∣ k = k a i b j = ∑ ( i ∣ j ) ∣ k = k a i b j = F W T ( C ) \begin{aligned}FWT(A) \times FWT(B) &=\left(\sum_{i \mid k=k} a_{i}\right)\left(\sum_{j \mid k=k} b_{j}\right) \\&=\sum_{i|k=k,\ j| k=k} a_{i} b_{j} \\&=\sum_{(i \mid j) \mid k=k} a_{i} b_{j} \\&=FWT(C)\end{aligned} FWT(A)×FWT(B)=ik=kaijk=kbj=ik=k, jk=kaibj=(ij)k=kaibj=FWT(C)


性质11.1: F W T ( A ± B ) = F W T ( A ) ± F W T ( B ) FWT(A\pm B)=FWT(A)\pm FWT(B) FWT(A±B)=FWT(A)±FWT(B)

根据 F W T FWT FWT 变换的定义我们可以将其看作是一个 A A A 序列的线性组合,故其加减法满足分配律。

由此我们可以得到 FWT 的递推式:

性质11.2:
F W T ( A ) = { ( F W T ( A 0 ) , F W T ( A 0 ) + F W T ( A 1 ) ) n > 1   A n = 0 FWT(A)=\begin{cases}(FWT(A_0),FWT(A_0)+FWT(A_1))& n>1\\\ A & n=0\end{cases} FWT(A)={(FWT(A0),FWT(A0)+FWT(A1)) An>1n=0
其中定义 A A A 2 k 2^k 2k 多项式, A 0 A_0 A0 代表 A A A 的系数序列的前半部分即前 2 k − 1 2^{k-1} 2k1 次项, A 1 A_1 A1 代表 A A A 的后半部分即后 2 k − 1 2^{k-1} 2k1 次项,也就是下标的最高位分别为 0 0 0 1 1 1 的两部分。

式中的括号运算定义为: A = ( B , C ) A=(B,C) A=(B,C)

表示 B B B 这个多项式后面接上 C C C 等于 A A A,展开后为:
( A , B ) = ( ( a 0 , a 1 , a 2 ⋯ a x − 1 ) , ( b 0 , b 1 , b 2 ⋯ b y − 1 ) ) = ( a 0 , a 1 , a 2 ⋯ a x − 1 , b 0 , b 1 , b 2 ⋯ b y − 1 ) \begin{aligned}(A, B) &=\left(\left(a_{0}, a_{1}, a_{2} \cdots a_{x-1}\right),\left(b_{0}, b_{1}, b_{2} \cdots b_{y-1}\right)\right) \\&=\left(a_{0}, a_{1}, a_{2} \cdots a_{x-1}, b_{0}, b_{1}, b_{2} \cdots b_{y-1}\right)\end{aligned} (A,B)=((a0,a1,a2ax1),(b0,b1,b2by1))=(a0,a1,a2ax1,b0,b1,b2by1)
可以理解为系数直接连起来。

考虑证明:

首先 n = 0 n=0 n=0 时显然成立。

我们知道 A 0 , A 1 A_0,A_1 A0,A1 实际上为下标的最高位分别为 0 0 0 1 1 1 的两部分,且除了最高位不同以外,其余的所有位,对于每一个下标 A 1 A_1 A1 都有一个 A 0 A_0 A0 与之相对应(仅最高位一个是 1 1 1 ,一个是 0 0 0)。

根据 FWT 的定义,合并之后左半部分下标的最高位仍然是 0 0 0,右半部分下标的最高位仍然是 1 1 1

首先对于左半部分:

由于 F W T ( A 1 ) FWT(A_1) FWT(A1) 的最高位一定为 1 1 1,而此时 j ∣ i j|i ji 的最高位不可能为 0 0 01 | 0 = 1),所以右半部分在合并之后对于左半部分是没有贡献的,故 F W T ( A ) 0 = F W T ( A 0 ) FWT(A)_0=FWT(A_0) FWT(A)0=FWT(A0)

而对于右半部分,如果左半部分的数满足 j ∣ i = i j|i=i ji=i,那么在 i i i 加上最高位 1 1 1 之后, j ∣ i = i j|i=i ji=i 仍然成立。而此时右半部分的原来的 F W T ( A 1 ) FWT(A_1) FWT(A1) 本来就对右半部分的数有贡献,故 F W T ( A ) 1 = F W T ( A 0 ) + F W T ( A 1 ) FWT(A)_1=FWT(A_0)+FWT(A_1) FWT(A)1=FWT(A0)+FWT(A1)

故我们将这两部分使用括号运算合并即可得到: F W T ( A ) = ( F W T ( A 0 ) , F W T ( A 0 ) + F W T ( A 1 ) ) FWT(A)=(FWT(A_0),FWT(A_0)+FWT(A_1)) FWT(A)=(FWT(A0),FWT(A0)+FWT(A1))

性质11.2 得证。


性质11.3: F W T ( A ∣ B ) = F W T ( A ) × F W T ( B ) FWT(A|B)=FWT(A)\times FWT(B) FWT(AB)=FWT(A)×FWT(B)

(注,这里的 × \times × 指对应系数相乘,见前排符号规定)

我们可以利用上面的 性质11.1 以及 性质11.2,使用数学归纳法证明:

F W T ( A ∣ B ) = F W T ( ( A ∣ B ) 0 , ( A ∣ B ) 1 ) = F W T ( A 0 ∣ B 0 , A 0 ∣ B 1 + A 1 ∣ B 0 + A 1 ∣ B 1 ) = ( F W T ( A 0 ∣ B 0 ) , F W T ( A 0 ∣ B 0 + A 0 ∣ B 1 + A 1 ∣ B 0 + A 1 ∣ B 1 ) ) = ( F W T ( A 0 ) × F W T ( B 0 ) , F W T ( A 0 ) × F W T ( B 0 ) + F W T ( A 0 ) × F W T ( B 1 ) + F W T ( A 1 ) × F W T ( B 0 ) + F W T ( A 1 ) × F W T ( B 1 ) ) = ( F W T ( A 0 ) × F W T ( B 0 ) , ( F W T ( A 0 ) + F W T ( A 1 ) ) × ( F W T ( B 0 ) + F W T ( B 1 ) ) ) = ( F W T ( A 0 ) , F W T ( A 0 + A 1 ) ) × ( F W T ( B 0 ) , F W T ( B 0 + B 1 ) ) = F W T ( A ) × F W T ( B ) \begin{aligned} FWT(A|B)=&FWT((A|B)_0,(A|B)_1)\\ =&FWT(A_0|B_0,A_0|B_1+A_1|B_0+A_1|B_1)\\ =&(FWT(A_0|B_0),FWT(A_0|B_0+A_0|B_1+A_1|B_0+A_1|B_1))\\ =&(FWT(A_0)\times FWT(B_0)\\&,FWT(A_0)\times FWT(B_0)+FWT(A_0)\times FWT(B_1)+FWT(A_1)\times FWT(B_0)+FWT(A_1)\times FWT(B_1))\\ =&(FWT(A_0)\times FWT(B_0),(FWT(A_0)+FWT(A_1))\times (FWT(B_0)+FWT(B_1)))\\ =&(FWT(A_0),FWT(A_0+A_1))\times (FWT(B_0),FWT(B_0+B_1))\\ =&FWT(A)\times FWT(B) \end{aligned} FWT(AB)=======FWT((AB)0,(AB)1)FWT(A0B0,A0B1+A1B0+A1B1)(FWT(A0B0),FWT(A0B0+A0B1+A1B0+A1B1))(FWT(A0)×FWT(B0),FWT(A0)×FWT(B0)+FWT(A0)×FWT(B1)+FWT(A1)×FWT(B0)+FWT(A1)×FWT(B1))(FWT(A0)×FWT(B0),(FWT(A0)+FWT(A1))×(FWT(B0)+FWT(B1)))(FWT(A0),FWT(A0+A1))×(FWT(B0),FWT(B0+B1))FWT(A)×FWT(B)


当然我们也可以使用定义将其展开来证明,这样看上去会会更加的清晰一些。

其中若 i ∣ k = k , j ∣ k = k → ( i ∣ j ) ∣ k = k i|k=k,j|k=k\to (i|j)|k=k ik=k,jk=k(ij)k=k

F W T ( A ) × F W T ( B ) = ( ∑ i ∣ 0 = 0 a i , ∑ i ∣ 1 = 1 a i , ∑ i ∣ 2 = 2 a i ⋯ ∑ i ∣ ( n − 1 ) = ( n − 1 ) a i ) × ( ∑ i ∣ 0 = 0 b i , ∑ i ∣ 1 = 1 b i , ∑ i ∣ 2 = 2 b i ⋯ ∑ i ∣ ( n − 1 ) = ( n − 1 ) b i ) = ( ( ∑ i ∣ 0 = 0 a i ) × ( ∑ j ∣ 0 = 0 b j ) , ( ∑ i ∣ 1 = 1 a i ) × ( ∑ j ∣ 1 = 1 b j ) , ( ∑ i ∣ 2 = 2 a i ) × ( ∑ j ∣ 2 = 2 b j ) ⋯ ( ∑ i ∣ ( n − 1 ) = ( n − 1 ) a i ) × ( ∑ j ∣ ( n − 1 ) = ( n − 1 ) b j ) ) = ( ∑ i ∣ j ∣ 0 = 0 a i × b j , ∑ i ∣ j ∣ 1 = 1 a i × b j , ∑ i ∣ j ∣ 2 = 2 a i × b j ⋯ ∑ i ∣ j ∣ ( n − 1 ) = ( n − 1 ) a i × b j ) = ( ∑ k ∣ 0 = 0 ∑ i ∣ j = k a i × b j , ∑ k ∣ 1 = 1 ∑ i ∣ j = k a i × b j , ∑ k ∣ 2 = 2 ∑ i ∣ j = k a i × b j ⋯ ∑ k ∣ ( n − 1 ) = ( n − 1 ) ∑ i ∣ j = k a i × b j ) = F W T ( A ∣ B ) \begin{aligned}FWT(A) \times F W T(B) &=\left(\sum_{i \mid 0=0} a_{i}, \sum_{i \mid 1=1} a_{i}, \sum_{i \mid 2=2} a_{i} \cdots \sum_{i \mid(n-1)=(n-1)} a_{i}\right) \times \left(\sum_{i \mid 0=0} b_{i}, \sum_{i \mid 1=1} b_{i}, \sum_{i \mid 2=2} b_{i} \cdots \sum_{i \mid(n-1)=(n-1)} b_{i}\right) \\&=\left(\left(\sum_{i \mid 0=0} a_{i}\right) \times \left(\sum_{j \mid 0=0} b_{j}\right),\left(\sum_{i \mid 1=1} a_{i}\right) \times \left(\sum_{j \mid 1=1} b_{j}\right),\left(\sum_{i \mid 2=2} a_{i}\right) \times \left(\sum_{j \mid 2=2} b_{j}\right) \cdots\left(\sum_{i \mid(n-1)=(n-1)} a_{i}\right) \times \left(\sum_{j \mid(n-1)=(n-1)} b_{j}\right)\right) \\&=\left(\sum_{i|j| 0=0} a_{i} \times b_{j}, \sum_{i|j| 1=1} a_{i}\times b_{j}, \sum_{i|j| 2=2} a_{i} \times b_{j} \cdots \sum_{i|j|(n-1)=(n-1)} a_{i} \times b_{j}\right) \\&=\left(\sum_{k \mid 0=0} \sum_{i \mid j=k} a_{i} \times b_{j}, \sum_{k \mid 1=1} \sum_{i \mid j=k} a_{i} \times b_{j}, \sum_{k \mid 2=2} \sum_{i \mid j=k} a_{i} \times b_{j} \cdots \sum_{k \mid(n-1)=(n-1)} \sum_{i \mid j=k} a_{i} \times b_{j}\right) \\&=F W T(A \mid B)\end{aligned} FWT(A)×FWT(B)=i0=0ai,i1=1ai,i2=2aii(n1)=(n1)ai×i0=0bi,i1=1bi,i2=2bii(n1)=(n1)bi=i0=0ai×j0=0bj,i1=1ai×j1=1bj,i2=2ai×j2=2bji(n1)=(n1)ai×j(n1)=(n1)bj=ij0=0ai×bj,ij1=1ai×bj,ij2=2ai×bjij(n1)=(n1)ai×bj=k0=0ij=kai×bj,k1=1ij=kai×bj,k2=2ij=kai×bjk(n1)=(n1)ij=kai×bj=FWT(AB)


至此,我们得到了与 FFT 类似的 FWT 的所有定义与性质。

根据 FFT 的流程,我们需要定义 IFWT,即逆沃尔什变换。

我们定义 I F W T ( F W T ( A ) ) = A IFWT(FWT(A))=A IFWT(FWT(A))=A

则:
I F W T ( A ) = { ( I F W T ( A 0 ) , I F W T ( A 1 ) − I F W T ( A 0 ) ) n > 1   A n = 0 IFWT(A)=\begin{cases}(IFWT(A_0),IFWT(A_1)-IFWT(A_0))&n>1\\\ A&n=0\end{cases} IFWT(A)={(IFWT(A0),IFWT(A1)IFWT(A0)) An>1n=0
考虑证明:

根据 性质11.1
∵ F W T ( A ) 0 = F W T ( A 0 ) ∴ A 0 = IFWT ⁡ ( F W T ( A 0 ) ) = IFWT ⁡ ( F W T ( A ) 0 ) ∵ F W T ( A ) 1 = F W T ( A 0 ) + F W T ( A 1 ) ∴ A 1 = I F W T ( F W T ( A 1 ) ) = I F W T ( F W T ( A ) 1 − F W T ( A ) 0 ) ∴ I F W T ( A ) = I F W T ( ( A 0 , A 1 ) ) = ( I F W T ( A 0 ) , I F W T ( A 1 ) − I F W T ( A 0 ) ) \begin{aligned}&\\&\because F W T(A)_{0}=F W T\left(A_{0}\right)\\&\therefore A_{0}=\operatorname{IFWT}\left(F W T\left(A_{0}\right)\right)=\operatorname{IFWT}\left(F W T(A)_{0}\right)\\&\because F W T(A)_{1}=F W T\left(A_{0}\right)+F W T\left(A_{1}\right)\\&\therefore A_{1}=I FW T\left(F W T\left(A_{1}\right)\right)=I FW T\left(F W T(A)_{1}-F W T(A)_{0}\right)\\& \therefore IFWT(A)=IFWT((A_0, A_1))=(IFWT(A_0),IFWT(A_1)-IFWT(A_0))\end{aligned} FWT(A)0=FWT(A0)A0=IFWT(FWT(A0))=IFWT(FWT(A)0)FWT(A)1=FWT(A0)+FWT(A1)A1=IFWT(FWT(A1))=IFWT(FWT(A)1FWT(A)0)IFWT(A)=IFWT((A0,A1))=(IFWT(A0),IFWT(A1)IFWT(A0))
其实看起来非常的形象,因为 IFWT 是 FWT 的逆运算,所以公式逆过来, + + + 变成 − - 就行了。

显然FWT与IFWT运算基本相同,实现的时候写成一个函数即可:

inline 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)
			for (int j = 0; j < k; ++ j)
				f[i + j + k] += f[i + j] * x;
}

0x12 与( and \text{and} and)卷积

同理,我们可以得到与卷积的定义式:
F W T ( A ) [ k ] = ∑ i & k = k a i FWT(A)[k]=\sum_{i\&k=k}a_i FWT(A)[k]=i&k=kai
以及 FWT 的递推式:
F W T ( A ) = { ( F W T ( A 0 ) + F W T ( A 1 ) , F W T ( A 1 ) ) n > 1   A n = 0 FWT(A)=\begin{cases}(FWT(A_0)+FWT(A_1),FWT(A_1))&n>1\\\ A &n=0\end{cases} FWT(A)={(FWT(A0)+FWT(A1),FWT(A1)) An>1n=0

证明同或卷积,序列 A A A 的右半部分任意一个下标 & \& & 左半部分即首位为 0 0 0 的数,得到的结果一定在 A A A 的左半部分,故 A 1 A_1 A1 对 左半部分有贡献,且一定对自己所在的右半部分有贡献。

性质12.1: F W T ( A & B ) = F W T ( A ) × F W T ( B ) FWT(A\&B)=FWT(A)\times FWT(B) FWT(A&B)=FWT(A)×FWT(B)

证明:

我们仍然利用性质11.1,使用数学归纳法证明
F W T ( A & B ) = F W T ( ( A & B ) 0 , ( A & B ) 1 ) = F W T ( A 0 & B 0 + A 0 & B 1 + A 1 & B 0 , A 1 & B 1 ) = ( F W T ( A 0 & B 0 + A 0 & B 1 + A 1 & B 0 + A 1 & B 1 ) , F W T ( A 1 & B 1 ) ) = ( ( F W T ( A 0 ) + F W T ( A 1 ) ) × ( F W T ( B 0 ) + F W T ( B 1 ) ) , F W T ( A 1 ) × F W T ( B 1 ) ) = ( F W T ( A 0 ) + F W T ( A 1 ) , F W T ( A 1 ) ) × ( F W T ( B 0 ) + F W T ( B 1 ) , F W T ( B 1 ) ) = F W T ( A ) × F W T ( B ) \begin{aligned} FWT(A\&B)&=FWT((A\&B)_0,(A\&B)_1)\\ &=FWT(A_0\&B_0+A_0\&B_1+A_1\&B_0,A_1\&B_1)\\ &=(FWT(A_0\&B_0+A_0\&B_1+A_1\&B_0+A_1\&B_1),FWT(A_1\&B_1))\\ &=((FWT(A_0)+FWT(A_1))\times (FWT(B_0)+FWT(B_1)),FWT(A_1)\times FWT(B_1))\\ &=(FWT(A_0)+FWT(A_1),FWT(A_1))\times (FWT(B_0)+FWT(B_1),FWT(B_1))\\ &=FWT(A)\times FWT(B) \end{aligned} FWT(A&B)=FWT((A&B)0,(A&B)1)=FWT(A0&B0+A0&B1+A1&B0,A1&B1)=(FWT(A0&B0+A0&B1+A1&B0+A1&B1),FWT(A1&B1))=((FWT(A0)+FWT(A1))×(FWT(B0)+FWT(B1)),FWT(A1)×FWT(B1))=(FWT(A0)+FWT(A1),FWT(A1))×(FWT(B0)+FWT(B1),FWT(B1))=FWT(A)×FWT(B)


或是继续展开证明:

F W T ( A ) × F W T ( B ) = ( ∑ i & 0 = 0 a i , ∑ i & 1 = 1 a i , ∑ i & 2 = 2 a i ⋯ ∑ i & ( n − 1 ) = ( n − 1 ) a i ) × ( ∑ i & 0 = 0 b i , ∑ i & 1 = 1 b i , ∑ i & 2 = 2 b i ⋯ ∑ i & ( n − 1 ) = ( n − 1 ) b i ) = ( ( ∑ i & 0 = 0 a i ) × ( ∑ j & 0 = 0 b j ) , ( ∑ i & 1 = 1 a i ) × ( ∑ j & 1 = 1 b j ) , ( ∑ i & 2 = 2 a i ) × ( ∑ j & 2 = 2 b j ) ⋯ ( ∑ i & ( n − 1 ) = ( n − 1 ) a i ) × ( ∑ j & ( n − 1 ) = ( n − 1 ) b j ) ) = ( ∑ i & j & 0 = 0 a i × b j , ∑ i & j & 1 = 1 a i × b j , ∑ i & j & 2 = 2 a i × b j ⋯ ∑ i & j & ( n − 1 ) = ( n − 1 ) a i × b j ) = ( ∑ k & 0 = 0 ∑ i & j = k a i ∗ b j , ∑ k & 1 = 1 ∑ i & j = k a i × b j , ∑ k & 2 = 2 ∑ i & j = k a i × b j ⋯ ∑ k & ( n − 1 ) = ( n − 1 ) ∑ i & j = k a i × b j ) = F W T ( A & B ) \begin{aligned}F W T(A) \times F W T(B)&=\left(\sum_{i \& 0=0} a_{i}, \sum_{i \& 1=1} a_{i}, \sum_{i \& 2=2} a_{i} \cdots \sum_{i \&(n-1)=(n-1)} a_{i}\right) \times \left(\sum_{i \& 0=0} b_{i}, \sum_{i \& 1=1} b_{i}, \sum_{i \& 2=2} b_{i} \cdots \sum_{i \&(n-1)=(n-1)} b_{i}\right)\\&=\left(\left(\sum_{i \& 0=0} a_{i}\right) \times \left(\sum_{j \& 0=0} b_{j}\right),\left(\sum_{i \& 1=1} a_{i}\right) \times \left(\sum_{j \& 1=1} b_{j}\right),\left(\sum_{i \& 2=2} a_{i}\right) \times \left(\sum_{j \& 2=2} b_{j}\right) \cdots\left(\sum_{i \&(n-1)=(n-1)} a_{i}\right) \times \left(\sum_{j \&(n-1)=(n-1)} b_{j}\right)\right)\\&=\left(\sum_{i \& j \& 0=0} a_{i} \times b_{j}, \sum_{i \& j \& 1=1} a_{i} \times b_{j}, \sum_{i \& j \& 2=2} a_{i} \times b_{j} \cdots \sum_{i \& j \&(n-1)=(n-1)} a_{i} \times b_{j}\right)\\&=\left(\sum_{k \& 0=0} \sum_{i \& j=k} a_{i} * b_{j}, \sum_{k \& 1=1} \sum_{i \& j=k} a_{i} \times b_{j}, \sum_{k \& 2=2} \sum_{i \& j=k} a_{i} \times b_{j} \cdots \sum_{k \&(n-1)=(n-1)} \sum_{i \& j=k} a_{i} \times b_{j}\right)\\&=F W T(A \& B)\end{aligned} FWT(A)×FWT(B)=i&0=0ai,i&1=1ai,i&2=2aii&(n1)=(n1)ai×i&0=0bi,i&1=1bi,i&2=2bii&(n1)=(n1)bi=(i&0=0ai)×j&0=0bj,(i&1=1ai)×j&1=1bj,(i&2=2ai)×j&2=2bji&(n1)=(n1)ai×j&(n1)=(n1)bj=i&j&0=0ai×bj,i&j&1=1ai×bj,i&j&2=2ai×bji&j&(n1)=(n1)ai×bj=k&0=0i&j=kaibj,k&1=1i&j=kai×bj,k&2=2i&j=kai×bjk&(n1)=(n1)i&j=kai×bj=FWT(A&B)

我们定义逆沃尔什变换 I F W T ( F W T ( A ) ) = A IFWT(FWT(A))=A IFWT(FWT(A))=A

则:
I F W T ( A ) = { ( I F W T ( A 0 ) − I F W T ( A 1 ) , I F W T ( A 1 ) ) n > 1   A n = 0 IFWT(A)=\begin{cases}(IFWT(A_0)-IFWT(A_1),IFWT(A_1))&n>1\\\ A&n=0\end{cases} IFWT(A)={(IFWT(A0)IFWT(A1),IFWT(A1)) An>1n=0

考虑证明:

n = 0 n=0 n=0 时正确性显然。

根据 性质11.1
F W T ( A ) 0 = F W T ( A 0 ) + F W T ( A 1 ) ∴ A 0 = I D F T ( F W T ( A 0 ) ) = I D F T ( F W T ( A ) 0 − F W T ( A ) 1 ) = I F W T ( A 0 ) − I F W T ( A 1 ) ∵ F W T ( A ) 1 = F W T ( A 1 ) ∴ A 1 = I D F T ( F W T ( A 1 ) ) = I D F T ( F W T ( A ) 1 ) ∴ I F W T ( A ) = I F W T ( ( A 0 , A 1 ) ) = ( I F W T ( A 0 ) − I F W T ( A 1 ) , I F W T ( A 1 ) ) \begin{aligned}& F W T(A)_{0}=F W T\left(A_{0}\right)+F W T\left(A_{1}\right)\\&\therefore A_{0}=I D F T\left(F W T\left(A_{0}\right)\right)=I D F T\left(F W T(A)_{0}-F W T(A)_{1}\right)=IFWT(A_0)-IFWT(A_1)\\&\because F W T(A)_{1}=F W T\left(A_{1}\right)\\&\therefore A_{1}=I D F T\left(F W T\left(A_{1}\right)\right)=I D F T\left(F W T(A)_{1}\right)\\& \therefore IFWT(A)=IFWT((A_0, A_1))=(IFWT(A_0)-IFWT(A_1),IFWT(A_1))\end{aligned} FWT(A)0=FWT(A0)+FWT(A1)A0=IDFT(FWT(A0))=IDFT(FWT(A)0FWT(A)1)=IFWT(A0)IFWT(A1)FWT(A)1=FWT(A1)A1=IDFT(FWT(A1))=IDFT(FWT(A)1)IFWT(A)=IFWT((A0,A1))=(IFWT(A0)IFWT(A1),IFWT(A1))
同或卷积,我们同样可以得到一份代码:

inline 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)
			for (int j = 0; j < k; ++ j)
				f[i+j] += f[i+j+k] * x;
}

0x13 异或( xor \text{xor} xor)卷积

异或卷积与或卷积、与卷积稍有不同。

我们定义函数 d ( x ) d(x) d(x) 表示 x x x 在二进制下 1 1 1 的数量

定义 FWT 变换为:
F W T ( A ) [ i ] = ∑ d ( j & i ) ≡ 0 m o d    2 A j − ∑ d ( k & i ) ≡ 1 m o d    2 A k FWT(A)[i]=\sum_{d(j\&i)\equiv0\mod 2}A_j-\sum_{d(k\&i)\equiv1\mod 2}A_k FWT(A)[i]=d(j&i)0mod2Ajd(k&i)1mod2Ak
则可得到递推式:
F W T ( A ) = { ( F W T ( A 0 ) + F W T ( A 1 ) , F W T ( A 0 ) − F W T ( A 1 ) ) n > 0   A n = 0 FWT(A)=\begin{cases}(FWT(A_0)+FWT(A_1),FWT(A_0)-FWT(A_1))&n>0\\\ A&n=0\end{cases} FWT(A)={(FWT(A0)+FWT(A1),FWT(A0)FWT(A1)) An>0n=0
考虑证明:

首先左半部分的公式为: F W T ( A 0 ) + F W T ( A 1 ) FWT(A_0)+FWT(A_1) FWT(A0)+FWT(A1)

因为 A 0 A_0 A0 即前 2 k − 1 2^{k-1} 2k1 项下标 [ 0 , 2 k − 1 ] [0,2^{k-1}] [0,2k1] 的最高位都为 0 0 0,故 A 0 A_0 A0 的下标与 A 0 A_0 A0 “与” 运算之后最高位不变,仍然是 0 0 0 ,所以要加上 A 0 A_0 A0 的贡献 F W T ( A 0 ) FWT(A_0) FWT(A0) A 1 A_1 A1 的下标在与 A 0 A_0 A0 “与”运算之后,最高位 1  and  0 = 0 1\ \text{and}\ 0=0 1 and 0=0 ,故后半部分也会对前半部分有贡献。

右半部分的公式为: F W T ( A 0 ) − F W T ( A 1 ) FWT(A_0)−FWT(A_1) FWT(A0)FWT(A1)

同理 A 0 A_0 A0 的下标和 A 1 A_1 A1 “与” 运算之后最高位保持不变。而 A 1 A_1 A1 的下标的最高位多了一个 1 1 1,“与” 上一个最高位为 1 1 1 的数之后奇偶性就变了,所以要取反 。


性质13.1: F W T ( A ⊕ B ) = F W T ( A ) × F W T ( B ) FWT(A\oplus B)=FWT(A)\times FWT(B) FWT(AB)=FWT(A)×FWT(B)

该性质在这里同样成立。

证明:
F W T ( A ⊕ B ) = F W T ( ( A ⊕ B ) 0 , ( A ⊕ B ) 1 ) = F W T ( A 0 ⊕ B 0 + A 1 ⊕ B 1 , A 0 ⊕ B 1 + A 1 ⊕ B 0 )   = ( F W T ( A 0 ⊕ B 0 + A 1 ⊕ B 1 + A 0 ⊕ B 1 + A 1 ⊕ B 0 ) , F W T ( A 0 ⊕ B 0 + A 1 ⊕ B 1 − A 0 ⊕ B 1 − A 1 ⊕ B 0 ) ) = ( ( F W T ( A 0 ) + F W T ( A 1 ) ) × ( F W T ( B 0 ) + F W T ( B 1 ) ) , ( F W T ( A 0 ) − F W T ( A 1 ) ) × ( F W T ( B 0 ) − F W T ( B 1 ) ) ) = ( F W T ( A 0 + A 1 ) , F W T ( A 0 − A 1 ) ) × ( F W T ( B 0 + B 1 ) , F W T ( B 0 − B 1 ) ) = F W T ( A ) × F W T ( B ) \begin{aligned} FWT(A\oplus B)&=FWT((A\oplus B)_0,(A\oplus B)_1)\\ &=FWT(A_0\oplus B_0+A_1\oplus B_1,A_0\oplus B_1+A_1\oplus B_0)\\\ &=(FWT(A_0\oplus B_0+A_1\oplus B_1+A_0\oplus B_1+A_1\oplus B_0),\\ &FWT(A_0\oplus B_0+A_1\oplus B_1-A_0\oplus B_1-A_1\oplus B_0))\\ &=((FWT(A_0)+FWT(A_1))\times (FWT(B_0)+FWT(B_1)),\\ &(FWT(A_0)-FWT(A_1))\times (FWT(B_0)-FWT(B_1)))\\ &=(FWT(A_0+A_1),FWT(A_0-A_1))\times (FWT(B_0+B_1),FWT(B_0-B_1))\\ &=FWT(A)\times FWT(B) \end{aligned} FWT(AB) =FWT((AB)0,(AB)1)=FWT(A0B0+A1B1,A0B1+A1B0)=(FWT(A0B0+A1B1+A0B1+A1B0),FWT(A0B0+A1B1A0B1A1B0))=((FWT(A0)+FWT(A1))×(FWT(B0)+FWT(B1)),(FWT(A0)FWT(A1))×(FWT(B0)FWT(B1)))=(FWT(A0+A1),FWT(A0A1))×(FWT(B0+B1),FWT(B0B1))=FWT(A)×FWT(B)

同样可以展开来证明:
F W T ( A × B ) = ( ∑ ( − 1 ) p c ( i & 0 ) a i , ∑ ( − 1 ) p c ( i & 1 ) a i ⋯ ∑ ( − 1 ) p c ( i & ( n − 1 ) ) a i ) × ( ∑ ( − 1 ) p c ( i & 0 ) b i , ∑ ( − 1 ) p c ( i & 1 ) b i ⋯ ∑ p ( − 1 ) p c ( i & ( n − 1 ) ) b i ) = ( ( ∑ ( − 1 ) p c ( i & 0 ) a i ) × ( ( ∑ ( − 1 ) p c ( j & 0 ) b j ) ) , ( ∑ ( − 1 ) p c ( i & 1 ) a i ) × ( ∑ ( − 1 ) p c ( j & 1 ) b j ) ⋯ ( ∑ ( − 1 ) p c ( i & ( n − 1 ) a i ) × ( ∑ ( − 1 ) p c ( j & ( n − 1 ) ) b j ) ) = ( ∑ ( − 1 ) p c ( i ⊕ j & 0 ) a i × b j , ( ∑ ( − 1 ) p c ( i ⊕ j & 1 ) a i × b j ⋯ ( ∑ ( − 1 ) p c ( i ⊕ j & ( n − 1 ) ) a i × b j ) = ( ∑ ( − 1 ) p c ( k & 0 ) ∑ i ⊕ j = k a i × b j , ∑ ( − 1 ) p c ( k & 1 ) ∑ i ⊕ j = k a i × b j ⋯ ∑ ( − 1 ) p c ( k & ( n − 1 ) ) ∑ i ⊕ j = k a i × b j ) = F W T ( A ⊕ B ) \begin{aligned}FWT(A\times B)&=\left(\sum(-1)^{p c(i \& 0)} a_{i}, \sum(-1)^{p c(i \& 1)} a_{i} \cdots \sum(-1)^{p c(i \&(n-1))} a_{i}\right) \times \left(\sum(-1)^{p c(i \& 0)} b_{i}, \sum(-1)^{p c(i \& 1)} b_{i} \cdots \sum_{ }^{p}\left.(-1)^{p c(i \&(n-1))} b_{i}\right)\right.\\&=\left(\left(\sum(-1)^{p c(i \& 0)} a_{i}\right) \times \left(\left(\sum(-1)^{p c(j \& 0)} b_{j}\right)\right),\left(\sum(-1)^{p c(i \& 1)} a_{i}\right) \times \left(\sum(-1)^{p c(j \& 1)} b_{j}\right) \cdots\left(\sum(-1)^{p c(i \&(n-1)}a_{i}\right)\right.\left.\left.\right. \times\left(\sum(-1)^{p c(j \&(n-1))} b_{j}\right)\right)\\&=\left(\sum(-1)^{p c(i \oplus j \& 0)} a_{i} \times b_{j},\left(\sum(-1)^{p c(i \oplus j \& 1)} a_{i} \times b_{j} \cdots\left(\sum(-1)^{p c(i \oplus j \&(n-1))} a_{i} \times b_{j}\right)\right.\right.\\&=\left(\sum(-1)^{p c(k \& 0)} \sum_{i \oplus j=k} a_{i} \times b_{j}, \sum(-1)^{p c(k \& 1)} \sum_{i \oplus j=k} a_{i} \times b_{j} \cdots \sum(-1)^{p c(k \&(n-1))} \sum_{i \oplus j=k} a_{i} \times b_{j}\right)\\&=F W T(A \oplus B)\end{aligned} FWT(A×B)=((1)pc(i&0)ai,(1)pc(i&1)ai(1)pc(i&(n1))ai)×((1)pc(i&0)bi,(1)pc(i&1)bip(1)pc(i&(n1))bi)=(((1)pc(i&0)ai)×(((1)pc(j&0)bj)),((1)pc(i&1)ai)×((1)pc(j&1)bj)((1)pc(i&(n1)ai)×((1)pc(j&(n1))bj))=((1)pc(ij&0)ai×bj,((1)pc(ij&1)ai×bj((1)pc(ij&(n1))ai×bj)=(1)pc(k&0)ij=kai×bj,(1)pc(k&1)ij=kai×bj(1)pc(k&(n1))ij=kai×bj=FWT(AB)
我们定义逆沃尔什变换 I F W T ( F W T ( A ) ) = A IFWT(FWT(A))=A IFWT(FWT(A))=A

则:
I F W T ( A ) = { ( I F W T ( A 0 + A 1 ) 2 , I F W T ( A 0 − A 1 ) 2 ) n > 1   A n = 0 IFWT(A)=\begin{cases}(\cfrac{IFWT(A_0+A_1)}{2},\cfrac{IFWT(A_0-A_1)}{2})&n>1\\\ A&n=0\end{cases} IFWT(A)=(2IFWT(A0+A1),2IFWT(A0A1)) An>1n=0
考虑证明:

n = 0 n=0 n=0 时正确性显然。

根据 性质11.1
∵ F W T ( A ) 0 = F W T ( A 0 ) + F W T ( A 1 ) , F W T ( A ) 1 = F W T ( A 0 ) − F W T ( A 1 ) ∴ A 0 = I D F T ( F W T ( A 0 ) ) = I D F T ( F W T ( A ) 0 + F W T ( A ) 1 2 ) A 1 = I D F T ( F W T ( A 1 ) ) = I D F T ( F W T ( A ) 0 − F W T ( A ) 1 2 ) ∴ I F W T ( A ) = I F W T ( ( A 0 , A 1 ) ) = ( I F W T ( A 0 + A 1 ) 2 , I F W T ( A 0 − A 1 ) 2 ) \begin{aligned} & \because F W T(A)_{0}=F W T\left(A_{0}\right)+F W T\left(A_{1}\right), F W T(A)_{1}=F W T\left(A_{0}\right)-F W T\left(A_{1}\right) \\&\therefore A_{0}=I D F T\left(F W T\left(A_{0}\right)\right)=I D F T\left(\frac{F W T(A)_{0}+F W T(A)_{1}}{2}\right)\\& A_{1}=I D F T\left(F W T\left(A_{1}\right)\right)= I D F T\left(\frac{F W T(A)_{0}-F W T(A)_{1}}{2}\right)\\& \therefore IFWT(A)=IFWT((A_0, A_1))=(\frac{IFWT(A_0+A_1)}{2},\frac{IFWT(A_0-A_1)}{2})\end{aligned} FWT(A)0=FWT(A0)+FWT(A1),FWT(A)1=FWT(A0)FWT(A1)A0=IDFT(FWT(A0))=IDFT(2FWT(A)0+FWT(A)1)A1=IDFT(FWT(A1))=IDFT(2FWT(A)0FWT(A)1)IFWT(A)=IFWT((A0,A1))=(2IFWT(A0+A1),2IFWT(A0A1))

inline 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)
			for (int j = 0; j < k; ++ j)
				f[i + j] += f[i + j + k],
				f[i + j + k] = f[i + j] - f[i + j + k] - f[i + j + k],
				f[i + j] *= x, f[i+j+k] *= x;
}

0x14 模板

luogu P4717 【模板】快速莫比乌斯/沃尔什变换 (FMT/FWT)

题目描述

给定长度为 2 n 2^n 2n 两个序列 A , B A,B A,B

C i = ∑ j ⊕ k = i A j × B k C_i=\sum_{j\oplus k = i}A_j \times B_k Ci=jk=iAj×Bk

分别当 ⊕ \oplus o r , a n d , x o r or,and,xor or,and,xor 时求出 C C C

输入格式

第一行一个数 n n n 。 第二行 2 n 2^n 2n 个数 A 0 . . A 2 n − 1 A_0..A_{2^n-1} A0..A2n1 第三行 2 n 2^n 2n 个数 B 0 . . B 2 n − 1 B_0..B_{2^n-1} B0..B2n1

输出格式

三行每行 2 n 2^n 2n 个数,分别代表 ⊕ \oplus o r , a n d , x o r or,and,xor or,and,xor C 0 . . C 2 n − 1 C_0..C_{2^n-1} C0..C2n1 的值   m o d     998244353 \bmod\ 998244353 mod 998244353

输入输出样例

输入

2
2 4 6 8
1 3 5 7

输出

2 22 46 250
88 64 112 56
100 92 68 60

说明/提示

n ≤ 17 n\le 17 n17

Code

数组版:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>

using namespace std;
typedef long long ll;
typedef int itn;
const int N = (1 << 18) + 7, mod = 998244353;
const ll INF = 4e18;

int n, m;
ll A[N], B[N], a[N], b[N];

ll qpow(ll a, ll b)
{
    ll res = 1;
    while(b) {
        if(b & 1) res = 1ll * res * a % mod;
        a = 1ll * a * a % mod;
        b >>= 1;
    }
    return res;
}

ll inv2 = qpow(2, mod - 2);

inline void in()
{
    for(int i = 0; i < n; ++ i)
        a[i] = A[i], b[i] = B[i];
}

inline void get()
{
    for(int i = 0; i < n; ++ i)
        a[i] = a[i] * b[i] % mod;
}

inline void out()
{
    for(int i = 0; i < n; ++ i)
        printf("%lld%s", (a[i] % mod + mod) % mod, i == (n - 1) ? "\n" : " ");
}


inline void OR(ll *f, int x = 1)//前半部分 f[i + j], 后半部分 f[i + j + k]
{
    for(int o = 2; o <= n; o <<= 1)
        for(int i = 0, k = o >> 1; i < n; i += o)
            for(int j = 0; j < k; ++ j)
                f[i + j + k] = (f[i + j] * x + f[i + j + k] + (x == 1 ? 0 : mod)) % mod;

}

inline void AND(ll *f, int x = 1)//前半部分 f[i + j],后半部分 f[i + j + k]
{
    for(int o = 2; o <= n; o <<= 1)
        for(int i = 0, k = o >> 1; i < n; i += o)
            for(int j = 0; j < k; ++ j)
                f[i + j] = (f[i + j] + f[i + j + k] * x + (x == 1 ? 0 : mod)) % mod;

}

inline void XOR(ll *f, int x = 1)//前半部分 f[i + j],后半部分 f[i + j + k]
{
    for(int o = 2; o <= n; o <<= 1)
        for(int i = 0, k = o >> 1; i < n; i += o)
            for(int j = 0; j < k; ++ j) {
                int X = f[i + j], Y = f[i + j + k];
                f[i + j] = (X + Y) % mod;
                f[i + j + k] = (X - Y % mod + mod) % mod;
                if(x != 1) {
                    f[i + j] = f[i + j] * inv2 % mod;
                    f[i + j + k] = f[i + j + k] * inv2 % mod;
                }
            }
}

int main()
{
    scanf("%d", &m);
    n = 1 << m;
    for(int i = 0; i < n; ++ i)
        scanf("%lld", &A[i]);
    for(int i = 0; i < n; ++ i)
        scanf("%lld", &B[i]);
    in(), OR(a), OR(b), get(), OR(a, -1), out();
    in(), AND(a), AND(b), get(), AND(a, -1), out();
    in(), XOR(a), XOR(b), get(), XOR(a, -1), out();
    return 0;
}

vector 版:

#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;

const int N = 50007, P = 998244353;
int n, m;

void add(int &x, int y) {
    (x += y) >= P && (x -= P);
}
void sub(int &x, int y) {
    (x -= y) < 0 && (x += P);
}
struct FWT {
    int extend(int n) {
        int N = 1;
        for (; N < n; N <<= 1);
        return N;
    }
    void FWTor( vector<int> &a, bool rev) {
        int n = a.size();
        for (int l = 2, m = 1; l <= n; l <<= 1, m <<= 1) {
            for (int j = 0; j < n; j += l) for (int i = 0; i < m; i++) {
                if (!rev) add(a[i + j + m], a[i + j]);
                else sub(a[i + j + m], a[i + j]);
            }
        }
    }
    void FWTand( vector<int> &a, bool rev) {
        int n = a.size();
        for (int l = 2, m = 1; l <= n; l <<= 1, m <<= 1) {
            for (int j = 0; j < n; j += l) for (int i = 0; i < m; i++) {
                if (!rev) add(a[i + j], a[i + j + m]);
                else sub(a[i + j], a[i + j + m]);
            }
        }
    }
    void FWTxor( vector<int> &a, bool rev) {
        int n = a.size(), inv2 = (P + 1) >> 1;
        for (int l = 2, m = 1; l <= n; l <<= 1, m <<= 1) {
            for (int j = 0; j < n; j += l) for (int i = 0; i < m; i++) {
                int x = a[i + j], y = a[i + j + m];
                if (!rev) {
                    a[i + j] = (x + y) % P;
                    a[i + j + m] = (x - y + P) % P;
                } else {
                    a[i + j] = 1LL * (x + y) * inv2 % P;
                    a[i + j + m] = 1LL * (x - y + P) * inv2 % P;
                }
            }
        }
    }
    vector<int> Or(vector<int> a1, vector<int> a2) {
        int n = max(a1.size(), a2.size()), N = extend(n);
        a1.resize(N), FWTor(a1, false);
        a2.resize(N), FWTor(a2, false);
        vector<int> A(N);
        for (int i = 0; i < N; i++) A[i] = 1LL * a1[i] * a2[i] % P;
        FWTor(A, true);
        return A;
    }
    vector<int> And(vector<int> a1, vector<int> a2) {
        int n =  max(a1.size(), a2.size()), N = extend(n);
        a1.resize(N), FWTand(a1, false);
        a2.resize(N), FWTand(a2, false);
        vector<int> A(N);
        for (int i = 0; i < N; i++) A[i] = 1LL * a1[i] * a2[i] % P;
        FWTand(A, true);
        return A;
    }
     vector<int> Xor(vector<int> a1, vector<int> a2) {
        int n = max(a1.size(), a2.size()), N = extend(n);
        a1.resize(N), FWTxor(a1, false);
        a2.resize(N), FWTxor(a2, false);
        vector<int> A(N);
        for (int i = 0; i < N; i++) A[i] = 1LL * a1[i] * a2[i] % P;
        FWTxor(A, true);
        return A;
    }
} fwt;

int main() {
    scanf("%d", &m);
    n = 1 << m;
    vector<int> a1(n), a2(n);
    for (int i = 0; i < n; i++) scanf("%d", &a1[i]);
    for (int i = 0; i < n; i++) scanf("%d", &a2[i]);
    vector<int> A;
    A = fwt.Or(a1, a2);
    for (int i = 0; i < n; i++) {
        printf("%d%c", A[i], " \n"[i == n - 1]);
    }
    A = fwt.And(a1, a2);
    for (int i = 0; i < n; i++) {
        printf("%d%c", A[i], " \n"[i == n - 1]);
    }
    A = fwt.Xor(a1, a2);
    for (int i = 0; i < n; i++) {
        printf("%d%c", A[i], " \n"[i == n - 1]);
    }
    return 0;
}

0x20 FMT与FMI(快速莫比乌斯变换与快速莫比乌斯反演)

待更…

0x30 竞赛例题选讲

鉴于篇幅原因,我将例题详解即代码分开成一篇新的博客,链接:

【解题报告】快速沃尔什变换FWT(ICPC / CCPC / NOIP真题集)

A、(牛客练习赛41 F)简单数学题

Link

https://ac.nowcoder.com/acm/contest/373/F

Problem

定义如下函数:
  f ( x ) = { 1 x = 1 max ⁡ { t   ∣   x   m o d   t = 0   & &   ∣ μ ( t ) ∣ = 1 } x ≥ 2 \ f(x)= \begin{cases} 1 & {x=1}\\ \max\{ t\ |\ {x \bmod t = 0}\ \&\&\ |\mu(t)| = 1 \}& {x \geq 2} \end{cases}  f(x)={1max{t  xmodt=0 && μ(t)=1}x=1x2

其中 μ ( t ) \mu(t) μ(t)为莫比乌斯函数,详见:https://en.wikipedia.org/wiki/M%C3%B6bius_function

对于任何整数   x \ x  x,若有 x = p 1 n 1 p 2 n 2 . . . p k n k x = p_{1}^{n_{1}}p_{2}^{n_{2}}...p_{k}^{n_{k}} x=p1n1p2n2...pknk ,其中   p i \ p_{i}  pi   x \ x  x   i \ i  i 大的质因子,则
g ( x ) = p 1 β ( n 1 ) p 2 β ( n 2 ) . . . p k β ( n k ) g(x) = p_{1}^{\beta(n_{1})}p_{2}^{\beta(n_{2})}...p_{k}^{\beta(n_{k})} g(x)=p1β(n1)p2β(n2)...pkβ(nk)

β ( x ) = { 0 x is even 1 x is odd \beta(x)= \begin{cases} 0& \text{x is even}\\ 1& \text{x is odd} \end{cases} β(x)={01x is evenx is odd

现在定义   F ( a , b , c ) = g ( f ( a ) ∗ f ( b ) ∗ f ( c ) ) \ F(a, b, c) = g(f(a)*f(b)*f(c))  F(a,b,c)=g(f(a)f(b)f(c))

并给出三个长度均为   n \ n  n 的数列
  A 1 A 2 A 3 . . . A n \ A_{1}A_{2}A_{3}...A_{n}  A1A2A3...An

  B 1 B 2 B 3 . . . B n \ B_{1}B_{2}B_{3}...B_{n}  B1B2B3...Bn

  C 1 C 2 C 3 . . . C n \ C_{1}C_{2}C_{3}...C_{n}  C1C2C3...Cn
对于某个整数   z \ z  z,如有   z = F ( A i , B j , C k ) ( 1 ≤ i , j , k ≤ n ) \ z = F(A_{i}, B_{j}, C_{k})(1 \leq i,j,k \leq n)  z=F(Ai,Bj,Ck)(1i,j,kn)

则称   G F ( i , j , k ) \ GF(i, j, k)  GF(i,j,k)为z的一种表示

  S \ S  S 集合为 S = { z ∣ z = F ( A i , B j , C k ) , 1 ≤ i , j , k ≤ n } S = \{ z|z=F(A_{i}, B_{j}, C_{k}),1 \leq i,j,k \leq n \} S={zz=F(Ai,Bj,Ck),1i,j,kn}   ∣ Z ∣ \ {|Z|}  Z   S \ S  S 中元素的个数

a n s = ∑ i = 1 ∣ Z ∣ z i k i ans = \sum_{i=1}^{|Z|}{z_{i} k_{i}} ans=i=1Zziki ,其中 z i z_{i} zi 是集合   S \ S  S 的第   i \ i  i 个元素,其中 k i k_{i} ki z i z_{i} zi 的不同的表示的个数。答案对   1 0 9 + 7 \ 10^{9}+7  109+7 取模。

注意:对于一个数   z \ z  z ,如果   z = F ( A i 1 , B j 1 , C k 1 ) ) = F ( A i 2 , B j 2 , C k 2 ) ) \ z = F(A_{i_{1}}, B_{j_{1}}, C_{k_{1}})) = F(A_{i_{2}}, B_{j_{2}}, C_{k_{2}}))  z=F(Ai1,Bj1,Ck1))=F(Ai2,Bj2,Ck2)) ,只要 i 1 ≠ i 2   o r   j 1 ≠ j 2   o r   k 1 ≠   k 2 i_{1}\neq i_{2}\ or\ j_{1}\neq j_{2}\ or\ k_{1}\neq \ k_{2} i1=i2 or j1=j2 or k1= k2 ,那么我们说 z z z 的这两种表示的两种不同的表示。

1 ≤ n ≤ 1 0 5 , A i , B i , C i ≤ 1 0 18 1\le n\le 10^5,A_i,B_i,C_i\le10^{18} 1n105,Ai,Bi,Ci1018,保证后三行输入的所有整数每个数的最大质因子不会超过   71 \ 71  71

Solution

A、(牛客练习赛41 F)简单数学题

B、(2018 ACM - ICPC shenyang I)Distance Between Sweethearts

Link

http://acm.hdu.edu.cn/showproblem.php?pid=6456

Problem

太长不看

给定6个不超过 2000 的整数: U I b o y , U A b o y , U G b o y UI_{boy}, UA_{boy}, UG_{boy} UIboy,UAboy,UGboy U I g i r l , U A g i r l , U G g i r l UI_{girl}, UA_{girl}, UG_{girl} UIgirl,UAgirl,UGgirl

定义 I g i r l , A g i r l , G g i r l I_{girl}, A_{girl}, G_{girl} Igirl,Agirl,Ggirl I b o y , A b o y , G b o y I_{boy}, A_{boy}, G_{boy} Iboy,Aboy,Gboy

给出了以下公式来测量我的爱人和我的心之间的距离:

d i s t a n c e ( b o y , g i r l ) = max ⁡ { ∣ I b o y − I g i r l ∣ , ∣ A b o y − A g i r l ∣ , ∣ G b o y − G g i r l ∣ } ⊕ I b o y ⊕ A b o y ⊕ G b o y ⊕ I g i r l ⊕ A g i r l ⊕ G g i r l distance(boy, girl) = \max\{|I_{boy} - I_{girl}|, |A_{boy} - A_{girl}|, |G_{boy} - G_{girl}|\} \oplus I_{boy} \oplus A_{boy} \oplus G_{boy} \oplus I_{girl} \oplus A_{girl} \oplus G_{girl} distance(boy,girl)=max{IboyIgirl,AboyAgirl,GboyGgirl}IboyAboyGboyIgirlAgirlGgirl

其中 m a x S max{S} maxS ∣ x ∣ |x| x ⊕ ⊕ 分别对应S的最大值、x的绝对值和位异或运算符。

它们满足以下限制条件:

0 ≤ I g i r l ≤ U I g i r l , 0 ≤ A g i r l ≤ U A g i r l , 0 ≤ G g i r l ≤ U G g i r l 0 \le I_{girl} \le UI_{girl}, 0 \le A_{girl} \le UA_{girl}, 0 \le G_{girl} \le UG_{girl} 0IgirlUIgirl,0AgirlUAgirl,0GgirlUGgirl

0 ≤ I b o y ≤ U I b o y , 0 ≤ A b o y ≤ U A b o y , 0 ≤ G b o y ≤ U G b o y 0 \le I_{boy} \le UI_{boy}, 0 \le A_{boy} \le UA_{boy}, 0 \le G_{boy} \le UG_{boy} 0IboyUIboy,0AboyUAboy,0GboyUGboy

它们的任意值在其限制条件下都可以是具有相同概率的整数。

现在我需要你的帮助来计算我们这对依然热恋的情侣的心之间距离的期望。

请你输出 ( 1 + U I b o y ) ( 1 + U A b o y ) ( 1 + U G b o y ) ( 1 + U I g i r l ) ( 1 + U A g i r l ) ( 1 + U G g i r l ) (1 + UI_{boy}) (1 + UA_{boy}) (1 + UG_{boy}) (1 + UI_{girl}) (1 + UA_{girl}) (1 + UG_{girl}) (1+UIboy)(1+UAboy)(1+UGboy)(1+UIgirl)(1+UAgirl)(1+UGgirl) 与距离的期望的乘积(保证答案一定是一个整数)。

保证答案在 2 64 − 1 2^{64} - 1 2641 以内。

Sample Input

3
3 1 2 4 3 3
1 2 1 2 1 3
3 2 5 4 3 5

Sample Output

Case #1: 3880
Case #2: 369
Case #3: 24728

Solution

B、(2018 ACM - ICPC shenyang I)Distance Between Sweethearts

C、(2019ACM - ICPC nanchang H)Another Sequence

Problem

给出一个长度为 n n n 的序列 a i a_i ai 和另一个长度为 n n n 的序列 b i b_i bi,现在定义 c i c_i ci 的生成方式如下:

  • c i c_i ci 的长度为 n 2 n^2 n2

  • c i ∗ ( n − 1 ) + j = a i ∣ b j c_{i * (n - 1) + j} = a_i | b_j ci(n1)+j=aibj

  • c i c_i ci 升序排序

现在要求支持两种操作:

  • c i c_i ci [ l , r ] [l,r] [l,r] 区间内的数开根
  • 询问 c x c_x cx 的数值。

Solution

C、(2019ACM - ICPC nanchang H)Another Sequence

D、(CROC 2016 - Final Round C)Binary Table

Link

https://codeforces.com/contest/662/problem/C

Problem

给你一个 n × m n\times m n×m 01 01 01 矩阵,每次操作:你可以挑选任意的某一行或者某一列翻转( 0 0 0 1 1 1 1 1 1 0 0 0 ),然后你需要使得整个矩阵的 1 1 1 的数量尽可能少,问你最少数量是多少。

Solution

D、(CROC 2016 - Final Round C)Binary Table

E、(HAOI2015)luogu P3175 按位或

Link

https://www.luogu.com.cn/problem/P3175

Problem

刚开始你有一个数字 0 0 0,每一秒钟你会随机选择一个 [ 0 , 2 n − 1 ] [0,2^n-1] [0,2n1] 的数字,与你手上的数字进行 或 操作。选择数字 i i i 的概率是 p i p_i pi。保证 0 ≤ p i ≤ 1 0\leq p_i \leq 1 0pi1 ∑ p i = 1 \sum p_i=1 pi=1。问期望多少秒后,你手上的数字变成 2 n − 1 2^n-1 2n1

Solution

E、(HAOI2015)luogu P3175 按位或

参考资料:

注,文中位运算卷积根据定义展开来证明的方法(就是那一大坨和式)参考:快速沃尔什变换(FWT) %%%

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁凡さん

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值