版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhouyuheng2003/article/details/84728063
1前言
在之前学完了FFT稍微码了一些题、也学习了一下NTT相关的知识之后,我觉得有必要学习一下FWT,这篇博客就是阐述我对FWT的理解的
2介绍
2.1解决的问题
对于FFT ,它的过程本质上是
c
n
=
∑
i
+
j
=
n
a
i
∗
b
j
c_n=\sum_{i+j=n}a_i*b_j
c n = i + j = n ∑ a i ∗ b j 然后考虑一下那个
i
+
j
=
n
i+j=n
i + j = n 的情况,如果换个符号,比如
i
−
j
=
n
i-j=n
i − j = n ,那么想必你也会做,只要把B翻转就好了 在NTT的题中,其实
i
∗
j
=
n
(
m
o
d
p
)
i*j=n\pmod p
i ∗ j = n ( m o d p ) ,在p有原根的时候 也可以做,直接把i位置的数换到
log
原
根
i
\log_{原根}i
log 原 根 i ,然后再做NTT,最后弄回来就好了 那么对于
i
∣
j
=
n
i|j=n
i ∣ j = n 、
i
&
j
=
n
i\& j=n
i & j = n 、
i
⊕
j
=
n
i\oplus j=n
i ⊕ j = n 的情况怎么办? 可以用FWT来解决 这篇文章中用到的只是快速沃尔什变换(FWT)的一个特殊情况,有兴趣可以去网上搜一搜广义的快速沃尔什是干什么的
2.2文章中有可能用到的符号&特殊说明
首先,这篇博客中提到的n(多项式的项数)如无特殊说明都是2的幂次 ,方便处理,如果不为2的幂次,可以在高次加0系数 然后,对于一些公式,你可能会觉得比较长,其实只是因为我列的项数比较多导致的,你可以只看第一项来看懂我在推什么
对于一个一般的多项式
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 ) = a 0 x 0 + a 1 x 1 + ⋅ ⋅ ⋅ + a n − 1 x n − 1 将其表示为
(
a
0
,
a
1
,
a
2
⋅
⋅
⋅
a
n
−
1
)
(a_0,a_1,a_2···a_{n-1})
( a 0 , a 1 , a 2 ⋅ ⋅ ⋅ a n − 1 )
定义多项式加法
C
(
x
)
=
A
(
x
)
+
B
(
x
)
=
(
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} C(x)&=A(x)+B(x)\\ &=(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})\\ \end{aligned}
C ( x ) = A ( x ) + B ( x ) = ( 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 )
多项式的减法把符号变成减号
C
(
x
)
=
A
(
x
)
−
B
(
x
)
=
(
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} C(x)&=A(x)-B(x)\\ &=(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})\\ \end{aligned}
C ( x ) = A ( x ) − B ( x ) = ( 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 )
多项式的对应系数相乘乘法(区别于那个FFT做的卷积的乘法 )
C
(
x
)
=
A
(
x
)
∗
B
(
x
)
=
(
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} C(x)&=A(x)*B(x)\\ &=(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})\\ \end{aligned}
C ( x ) = A ( x ) ∗ B ( x ) = ( 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 )
对于多项式的一个操作
@
(
@
∈
{
∣
(
或
)
,
&
(
与
)
,
⊕
(
异
或
)
}
)
@(@ \in \left\{ |(或),\&(与),\oplus(异或) \right\})
@ ( @ ∈ { ∣ ( 或 ) , & ( 与 ) , ⊕ ( 异 或 ) } ) ,请看清楚,这里的是卷积,FFT做的多项式乘法相当于这里的符号用“+”,然而多项式的“+”已经被定义过了,前面的系数相乘乘法事实上不应该用那个符号 ,所以没有列出
C
(
x
)
=
A
(
x
)
@
B
(
x
)
=
(
a
0
,
a
1
,
a
2
⋅
⋅
⋅
a
n
−
1
)
@
(
b
0
,
b
1
,
b
2
⋅
⋅
⋅
b
n
−
1
)
=
(
∑
i
@
j
=
0
a
i
∗
b
j
,
∑
i
@
j
=
1
a
i
∗
b
j
,
∑
i
@
j
=
2
a
i
∗
b
j
⋅
⋅
⋅
∑
i
@
j
=
n
−
1
a
i
∗
b
j
)
\begin{aligned} C(x)&=A(x)@B(x)\\ &=(a_0,a_1,a_2···a_{n-1})@(b_0,b_1,b_2···b_{n-1})\\ &=(\sum _{i@j=0}a_i*b_j,\sum _{i@j=1}a_i*b_j,\sum _{i@j=2}a_i*b_j···\sum _{i@j=n-1}a_i*b_j)\\ \end{aligned}
C ( x ) = A ( x ) @ B ( x ) = ( a 0 , a 1 , a 2 ⋅ ⋅ ⋅ a n − 1 ) @ ( b 0 , b 1 , b 2 ⋅ ⋅ ⋅ b n − 1 ) = ( i @ j = 0 ∑ a i ∗ b j , i @ j = 1 ∑ a i ∗ b j , i @ j = 2 ∑ a i ∗ b j ⋅ ⋅ ⋅ i @ j = n − 1 ∑ a i ∗ b j ) 特殊的,这里的
@
@
@ 运算具有分配律,即
(
A
+
B
)
@
C
=
A
@
C
+
B
@
C
(A+B)@C=A@C+B@C
( A + B ) @ C = A @ C + B @ C ,至于证明也非常方便:
∑
i
@
j
=
x
(
a
i
+
b
i
)
∗
c
j
=
∑
i
@
j
=
x
(
a
i
+
b
i
)
∗
c
j
=
∑
i
@
j
=
x
(
a
i
∗
c
j
+
b
i
∗
c
j
)
=
∑
i
@
j
=
x
a
i
∗
c
j
+
∑
i
@
j
=
x
b
i
∗
c
j
\begin{aligned} \sum _{i@j=x}(a_i+b_i)*c_j&=\sum _{i@j=x}(a_i+b_i)*c_j\\ &=\sum _{i@j=x}(a_i*c_j+b_i*c_j)\\ &=\sum _{i@j=x}a_i*c_j+\sum _{i@j=x}b_i*c_j \end{aligned}
i @ j = x ∑ ( a i + b i ) ∗ c j = i @ j = x ∑ ( a i + b i ) ∗ c j = i @ j = x ∑ ( a i ∗ c j + b i ∗ c j ) = i @ j = x ∑ a i ∗ c j + i @ j = x ∑ b i ∗ c j
另外对于一个多项式
A
A
A ,设
n
=
2
k
n=2^k
n = 2 k ,定义
A
0
A_0
A 0 为
A
A
A 的前
2
k
−
1
2^{k-1}
2 k − 1 个系数、定义
A
1
A_1
A 1 为
A
A
A 的后
2
k
−
1
2^{k-1}
2 k − 1 个系数 定义运算
A
=
(
B
,
C
)
A=(B,C)
A = ( B , C ) 表示B这个多项式后面接上C等于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)&=((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})\\ \end{aligned}
( 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 )
2.3FWT的大致思路
假设我们现在有两个多项式
A
A
A 、
B
B
B 以及一个位运算符
@
@
@ ,思路和FFT相似,先求出某个多项式
F
W
T
(
A
)
FWT(A)
F W T ( A ) 和
F
W
T
(
B
)
FWT(B)
F W T ( B ) ,然后对应相乘得到多项式
F
W
T
(
C
)
FWT(C)
F W T ( C ) ,最后进行
I
F
W
T
IFWT
I F W T ,得出结果
C
C
C
3实现
3.1or运算
3.1.1构造
先来讲or运算吧 现在要求的是:
c
n
=
∑
i
∣
j
=
n
a
i
b
j
c_n=\sum_{i|j=n}a_ib_j
c n = i ∣ j = n ∑ a i b j 定义FWT(A):
F
W
T
(
A
)
=
(
∑
i
∣
0
=
0
a
i
,
∑
i
∣
1
=
1
a
i
,
∑
i
∣
2
=
2
a
i
⋅
⋅
⋅
∑
i
∣
(
n
−
1
)
=
(
n
−
1
)
a
i
)
\begin{aligned} FWT(A)=(\sum_{i|0=0}a_i,\sum_{i|1=1}a_i,\sum_{i|2=2}a_i···\sum_{i|(n-1)=(n-1)}a_i) \end{aligned}
F W T ( A ) = ( i ∣ 0 = 0 ∑ a i , i ∣ 1 = 1 ∑ a i , i ∣ 2 = 2 ∑ a i ⋅ ⋅ ⋅ i ∣ ( n − 1 ) = ( n − 1 ) ∑ a i ) 容易发现一件事:
F
W
T
(
A
∣
B
)
=
F
W
T
(
A
)
∗
F
W
T
(
B
)
FWT(A|B)=FWT(A)*FWT(B)
F W T ( A ∣ B ) = F W T ( A ) ∗ F W T ( 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} FWT(A)*FWT(B)&=(\sum_{i|0=0}a_i,\sum_{i|1=1}a_i,\sum_{i|2=2}a_i···\sum_{i|(n-1)=(n-1)}a_i)*(\sum_{i|0=0}b_i,\sum_{i|1=1}b_i,\sum_{i|2=2}b_i···\sum_{i|(n-1)=(n-1)}b_i)\\ &=((\sum_{i|0=0}a_i)*(\sum_{j|0=0}b_j),(\sum_{i|1=1}a_i)*(\sum_{j|1=1}b_j),(\sum_{i|2=2}a_i)*(\sum_{j|2=2}b_j)···(\sum_{i|(n-1)=(n-1)}a_i)*(\sum_{j|(n-1)=(n-1)}b_j))\\ &=(\sum_{i|j|0=0}a_i*b_j,\sum_{i|j|1=1}a_i*b_j,\sum_{i|j|2=2}a_i*b_j···\sum_{i|j|(n-1)=(n-1)}a_i*b_j)\\ &=(\sum_{k|0=0}\sum_{i|j=k}a_i*b_j,\sum_{k|1=1}\sum_{i|j=k}a_i*b_j,\sum_{k|2=2}\sum_{i|j=k}a_i*b_j···\sum_{k|(n-1)=(n-1)}\sum_{i|j=k}a_i*b_j)\\ &=FWT(A|B) \end{aligned}
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 ) 当然这个的证明还有其它的很多方法,我觉得我的这个证明还是比较清楚的 也就是说,现在:
问题一: 已知一个多项式A,求FWT(A) 即FWT
问题二: 已知FWT(A),求A 即IFWT
解决这两个问题,我们就能够:
已知A,B
FWT,求出FWT(A),FWT(B)
对应系数相乘,求出FWT(A|B)
IFWT,求出A|B
3.1.2计算
我们可以递归定义
F
W
T
(
A
)
=
{
(
F
W
T
(
A
0
)
,
F
W
T
(
A
0
+
A
1
)
)
(
n
≠
1
)
A
(
n
=
1
)
FWT(A)=\begin{cases} (FWT(A_0),FWT(A_0+A_1))(n\ne1)\\ A(n=1) \end{cases}
F W T ( A ) = { ( F W T ( A 0 ) , F W T ( A 0 + A 1 ) ) ( n ̸ = 1 ) A ( n = 1 ) 这么定义的原因:因为
A
0
A_0
A 0 的编号的最高位都是0,
A
1
A_1
A 1 的编号与
A
0
A_0
A 0 的编号的最高位变成1的结果一一对应,因为是or运算,所以
A
0
A_0
A 0 能到
A
1
A_1
A 1 里一一对应的贡献 然后考虑
I
F
W
T
IFWT
I F W T (定义
I
F
W
T
(
F
W
T
(
A
)
)
=
A
IFWT(FWT(A))=A
I F W T ( F W T ( A ) ) = A ),由于
F
W
T
(
A
+
B
)
=
F
W
T
(
A
)
+
F
W
T
(
B
)
FWT(A+B)=FWT(A)+FWT(B)
F W T ( A + B ) = F W T ( A ) + F W T ( B ) (这个证明不用说了吧,看我的定义,这个相当于乘法分配律拆一下就好了),可以列出
I
F
W
T
IFWT
I F W T 的式子,推导: 已知
F
W
T
(
A
)
0
FWT(A)_0
F W T ( A ) 0 、
F
W
T
(
A
)
1
FWT(A)_1
F W T ( A ) 1 ,求
A
0
A_0
A 0 、
A
1
A_1
A 1
∵
F
W
T
(
A
)
0
=
F
W
T
(
A
0
)
∴
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
=
F
W
T
(
A
0
)
+
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
−
F
W
T
(
A
)
0
)
\because FWT(A)_0=FWT(A_0)\\ \therefore A_0=IDFT(FWT(A_0))=IDFT(FWT(A)_0)\\ \because FWT(A)_1=FWT(A_0)+FWT(A_1)\\ \therefore A_1= IDFT(FWT(A_1))=IDFT(FWT(A)_1-FWT(A)_0)
∵ F W T ( A ) 0 = F W T ( A 0 ) ∴ 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 = F W T ( A 0 ) + 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 − F W T ( A ) 0 )
总结:
I
F
W
T
(
A
)
=
{
(
I
F
W
T
(
A
0
)
,
I
F
W
T
(
A
1
−
A
0
)
)
(
n
≠
1
)
A
(
n
=
1
)
IFWT(A)=\begin{cases} (IFWT(A_0),IFWT(A_1-A_0))(n\ne1)\\ A(n=1) \end{cases}
I F W T ( A ) = { ( I F W T ( A 0 ) , I F W T ( A 1 − A 0 ) ) ( n ̸ = 1 ) A ( n = 1 ) 然后就可以写代码了(代码和FFT有点像)
inline void FWT ( LL* A, const int fla)
{
for ( rg int i= 1 ; i< lenth; i<<= 1 )
for ( rg int j= 0 ; j< lenth; j+ = ( i<< 1 ) )
for ( rg int k= 0 ; k< i; k++ )
A[ j+ k+ i] + = A[ j+ k] * fla;
}
然后or运算的FWT就没了
3.2and运算
3.2.1构造
and其实和or差的不多 现在要求的是:
c
n
=
∑
i
&
j
=
n
a
i
b
j
c_n=\sum_{i\&j=n}a_ib_j
c n = i & j = n ∑ a i b j 同样定义FWT(A):
F
W
T
(
A
)
=
(
∑
i
&
0
=
0
a
i
,
∑
i
&
1
=
1
a
i
,
∑
i
&
2
=
2
a
i
⋅
⋅
⋅
∑
i
&
(
n
−
1
)
=
(
n
−
1
)
a
i
)
\begin{aligned} FWT(A)=(\sum_{i\&0=0}a_i,\sum_{i\&1=1}a_i,\sum_{i\&2=2}a_i···\sum_{i\&(n-1)=(n-1)}a_i) \end{aligned}
F W T ( A ) = ( i & 0 = 0 ∑ a i , i & 1 = 1 ∑ a i , i & 2 = 2 ∑ a i ⋅ ⋅ ⋅ i & ( n − 1 ) = ( n − 1 ) ∑ a i ) 同样的:
F
W
T
(
A
&
B
)
=
F
W
T
(
A
)
∗
F
W
T
(
B
)
FWT(A\&B)=FWT(A)*FWT(B)
F W T ( A & B ) = F W T ( A ) ∗ F W T ( 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} FWT(A)*FWT(B)&=(\sum_{i\&0=0}a_i,\sum_{i\&1=1}a_i,\sum_{i\&2=2}a_i···\sum_{i\&(n-1)=(n-1)}a_i)*(\sum_{i\&0=0}b_i,\sum_{i\&1=1}b_i,\sum_{i\&2=2}b_i···\sum_{i\&(n-1)=(n-1)}b_i)\\ &=((\sum_{i\&0=0}a_i)*(\sum_{j\&0=0}b_j),(\sum_{i\&1=1}a_i)*(\sum_{j\&1=1}b_j),(\sum_{i\&2=2}a_i)*(\sum_{j\&2=2}b_j)···(\sum_{i\&(n-1)=(n-1)}a_i)*(\sum_{j\&(n-1)=(n-1)}b_j))\\ &=(\sum_{i\&j\&0=0}a_i*b_j,\sum_{i\&j\&1=1}a_i*b_j,\sum_{i\&j\&2=2}a_i*b_j···\sum_{i\&j\&(n-1)=(n-1)}a_i*b_j)\\ &=(\sum_{k\&0=0}\sum_{i\&j=k}a_i*b_j,\sum_{k\&1=1}\sum_{i\&j=k}a_i*b_j,\sum_{k\&2=2}\sum_{i\&j=k}a_i*b_j···\sum_{k\&(n-1)=(n-1)}\sum_{i\&j=k}a_i*b_j)\\ &=FWT(A\&B) \end{aligned}
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 ) 然后没啦
3.2.2计算
我们一样可以递归定义
F
W
T
(
A
)
=
{
(
F
W
T
(
A
0
+
A
1
)
,
F
W
T
(
A
1
)
)
(
n
≠
1
)
A
(
n
=
1
)
FWT(A)=\begin{cases} (FWT(A_0+A_1),FWT(A_1))(n\ne1)\\ A(n=1) \end{cases}
F W T ( A ) = { ( F W T ( A 0 + A 1 ) , F W T ( A 1 ) ) ( n ̸ = 1 ) A ( n = 1 ) 这么定义的原因(其实和or差不多 ):因为
A
0
A_0
A 0 的编号的最高位都是0,
A
1
A_1
A 1 的编号与
A
0
A_0
A 0 的编号的最高位变成1的结果一一对应,因为是and运算,所以
A
1
A_1
A 1 能到
A
0
A_0
A 0 里一一对应的贡献 然后是
I
F
W
T
IFWT
I F W T ,推导: 已知
F
W
T
(
A
)
0
FWT(A)_0
F W T ( A ) 0 、
F
W
T
(
A
)
1
FWT(A)_1
F W T ( A ) 1 ,求
A
0
A_0
A 0 、
A
1
A_1
A 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
)
∵
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
)
\because FWT(A)_0=FWT(A_0)+FWT(A_1)\\ \therefore A_0=IDFT(FWT(A_0))=IDFT(FWT(A)_0-FWT(A)_1)\\ \because FWT(A)_1=FWT(A_1)\\ \therefore A_1= IDFT(FWT(A_1))=IDFT(FWT(A)_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 ) ∵ 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
1
)
)
(
n
≠
1
)
A
(
n
=
1
)
IFWT(A)=\begin{cases} (IFWT(A_0-A_1),IFWT(A_1))(n\ne1)\\ A(n=1) \end{cases}
I F W T ( A ) = { ( I F W T ( A 0 − A 1 ) , I F W T ( A 1 ) ) ( n ̸ = 1 ) A ( n = 1 ) 然后上代码
inline void FWT ( LL* A, const int fla)
{
for ( rg int i= 1 ; i< lenth; i<<= 1 )
for ( rg int j= 0 ; j< lenth; j+ = ( i<< 1 ) )
for ( rg int k= 0 ; k< i; k++ )
A[ j+ k] + = A[ j+ k+ i] * fla;
}
完
3.3xor运算
3.3.1构造
哦不,这是最烦的xor运算,我的思路在xor下是最烦的 现在要求的是:
c
n
=
∑
i
⊕
j
=
n
a
i
b
j
c_n=\sum_{i\oplus j=n}a_ib_j
c n = i ⊕ j = n ∑ a i b j 也要定义FWT(A),然而定义有一点烦: update:这是新版本,比较清晰易懂:
符号说明:
p
o
p
c
o
u
n
t
(
x
)
popcount(x)
p o p c o u n t ( x ) 等于x在二进制下1的数量,我在下面简写为
p
c
(
x
)
pc(x)
p c ( x )
F
W
T
(
A
)
=
(
∑
(
−
1
)
p
c
(
i
&
0
)
a
i
,
∑
(
−
1
)
p
c
(
i
&
1
)
a
i
⋅
⋅
⋅
∑
(
−
1
)
p
c
(
i
&
(
n
−
1
)
)
a
i
)
FWT(A)=(\sum (-1)^{pc(i\&0)}a_i,\sum (-1)^{pc(i\&1)}a_i···\sum (-1)^{pc(i\&(n-1))}a_i)
F W T ( A ) = ( ∑ ( − 1 ) p c ( i & 0 ) a i , ∑ ( − 1 ) p c ( i & 1 ) a i ⋅ ⋅ ⋅ ∑ ( − 1 ) p c ( i & ( n − 1 ) ) a i ) 证明:
F
W
T
(
A
⊕
B
)
=
F
W
T
(
A
)
∗
F
W
T
(
B
)
FWT(A\oplus B)=FWT(A)*FWT(B)
F W T ( A ⊕ B ) = F W T ( A ) ∗ F W T ( B )
F
W
T
(
A
)
∗
F
W
T
(
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
⋅
⋅
⋅
∑
(
−
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)*FWT(B)&=(\sum (-1)^{pc(i\&0)}a_i,\sum (-1)^{pc(i\&1)}a_i···\sum (-1)^{pc(i\&(n-1))}a_i)*(\sum (-1)^{pc(i\&0)}b_i,\sum (-1)^{pc(i\&1)}b_i···\sum (-1)^{pc(i\&(n-1))}b_i)\\ &=((\sum (-1)^{pc(i\&0)}a_i)*((\sum (-1)^{pc(j\&0)}b_j)),(\sum (-1)^{pc(i\&1)}a_i)*(\sum (-1)^{pc(j\&1)}b_j)···(\sum (-1)^{pc(i\&(n-1))}a_i)*(\sum (-1)^{pc(j\&(n-1))}b_j))\\ &=(\sum (-1)^{pc(i\oplus j\&0)}a_i*b_j,(\sum (-1)^{pc(i\oplus j\&1)}a_i*b_j···(\sum (-1)^{pc(i\oplus j\&(n-1))}a_i*b_j)\\ &=(\sum (-1)^{pc(k\&0)}\sum _{i\oplus j=k}a_i*b_j,\sum (-1)^{pc(k\&1)}\sum _{i\oplus j=k}a_i*b_j···\sum (-1)^{pc(k\&(n-1))}\sum _{i\oplus j=k}a_i*b_j)\\ &=FWT(A\oplus B) \end{aligned}
F W T ( A ) ∗ F W T ( 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 ⋅ ⋅ ⋅ ∑ ( − 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 )
下面是老版本,是一个不太标准的形式,你可以直接跳到3.3.2
符号说明:
p
o
p
c
o
u
n
t
(
x
)
popcount(x)
p o p c o u n t ( x ) 等于x在二进制下1的数量,我在下面简写为
p
c
(
x
)
pc(x)
p c ( x ) 逻辑运算符a?b:c 代表若a为真,那么值为b,若为假,值为c
F
W
T
(
A
)
=
(
∑
p
c
(
i
&
0
)
m
o
d
2
=
=
0
?
a
i
:
−
a
i
,
∑
p
c
(
i
&
1
)
m
o
d
2
=
=
0
?
a
i
:
−
a
i
,
∑
p
c
(
i
&
2
)
m
o
d
2
=
=
0
?
a
i
:
−
a
i
⋅
⋅
⋅
∑
p
c
(
i
&
(
n
−
1
)
)
m
o
d
2
=
=
0
?
a
i
:
−
a
i
)
FWT(A)=(\sum pc(i\&0)mod\ 2==0? a_i:-a_i,\sum pc(i\&1)mod\ 2==0? a_i:-a_i,\sum pc(i\&2)mod\ 2==0? a_i:-a_i···\sum pc(i\&(n-1))mod\ 2==0? a_i:-a_i)
F W T ( A ) = ( ∑ p c ( i & 0 ) m o d 2 = = 0 ? a i : − a i , ∑ p c ( i & 1 ) m o d 2 = = 0 ? a i : − a i , ∑ p c ( i & 2 ) m o d 2 = = 0 ? a i : − a i ⋅ ⋅ ⋅ ∑ p c ( i & ( n − 1 ) ) m o d 2 = = 0 ? a i : − a i ) 不 容易发现一件事:
F
W
T
(
A
⊕
B
)
=
F
W
T
(
A
)
∗
F
W
T
(
B
)
FWT(A\oplus B)=FWT(A)*FWT(B)
F W T ( A ⊕ B ) = F W T ( A ) ∗ F W T ( B ) 证明:
F
W
T
(
A
)
∗
F
W
T
(
B
)
=
(
∑
p
c
(
i
&
0
)
m
o
d
2
=
=
0
?
a
i
:
−
a
i
,
∑
p
c
(
i
&
1
)
m
o
d
2
=
=
0
?
a
i
:
−
a
i
,
∑
p
c
(
i
&
2
)
m
o
d
2
=
=
0
?
a
i
:
−
a
i
⋅
⋅
⋅
∑
p
c
(
i
&
(
n
−
1
)
)
m
o
d
2
=
=
0
?
a
i
:
−
a
i
)
∗
(
∑
p
c
(
i
&
0
)
m
o
d
2
=
=
0
?
b
i
:
−
b
i
,
∑
p
c
(
i
&
1
)
m
o
d
2
=
=
0
?
b
i
:
−
b
i
,
∑
p
c
(
i
&
2
)
m
o
d
2
=
=
0
?
b
i
:
−
b
i
⋅
⋅
⋅
∑
p
c
(
i
&
(
n
−
1
)
)
m
o
d
2
=
=
0
?
b
i
:
−
b
i
)
=
(
(
∑
p
c
(
i
&
0
)
m
o
d
2
=
=
0
?
a
i
:
−
a
i
)
∗
(
∑
p
c
(
j
&
0
)
m
o
d
2
=
=
0
?
b
j
:
−
b
j
)
,
(
∑
p
c
(
i
&
1
)
m
o
d
2
=
=
0
?
a
i
:
−
a
i
)
∗
(
∑
p
c
(
j
&
1
)
m
o
d
2
=
=
0
?
b
j
:
−
b
j
)
,
(
∑
p
c
(
i
&
2
)
m
o
d
2
=
=
0
?
a
i
:
−
a
i
)
∗
(
∑
p
c
(
j
&
2
)
m
o
d
2
=
=
0
?
b
j
:
−
b
j
)
⋅
⋅
⋅
(
∑
p
c
(
i
&
(
n
−
1
)
)
m
o
d
2
=
=
0
?
a
i
:
−
a
i
)
∗
(
∑
p
c
(
j
&
(
n
−
1
)
)
m
o
d
2
=
=
0
?
b
j
:
−
b
j
)
)
=
(
∑
p
c
(
(
i
⊕
j
)
&
0
)
m
o
d
2
=
=
0
?
a
i
∗
b
j
:
−
a
i
∗
b
j
,
∑
p
c
(
(
i
⊕
j
)
&
1
)
m
o
d
2
=
=
0
?
a
i
∗
b
j
:
−
a
i
∗
b
j
,
∑
p
c
(
(
i
⊕
j
)
&
2
)
m
o
d
2
=
=
0
?
a
i
∗
b
j
:
−
a
i
∗
b
j
⋅
⋅
⋅
∑
p
c
(
(
i
⊕
j
)
&
(
n
−
1
)
)
m
o
d
2
=
=
0
?
a
i
∗
b
j
:
−
a
i
∗
b
j
)
=
(
∑
p
c
(
k
&
0
)
m
o
d
2
=
=
0
?
∑
i
⊕
j
=
k
a
i
∗
b
j
:
−
∑
i
⊕
j
=
k
a
i
∗
b
j
,
∑
p
c
(
k
&
1
)
m
o
d
2
=
=
0
?
∑
i
⊕
j
=
k
a
i
∗
b
j
:
−
∑
i
⊕
j
=
k
a
i
∗
b
j
,
∑
p
c
(
k
&
2
)
m
o
d
2
=
=
0
?
∑
i
⊕
j
=
k
a
i
∗
b
j
:
−
∑
i
⊕
j
=
k
a
i
∗
b
j
⋅
⋅
⋅
∑
p
c
(
k
&
(
n
−
1
)
)
m
o
d
2
=
=
0
?
∑
i
⊕
j
=
k
a
i
∗
b
j
:
−
∑
i
⊕
j
=
k
a
i
∗
b
j
)
=
F
W
T
(
A
⊕
B
)
\begin{aligned} FWT(A)*FWT(B)&=(\sum pc(i\&0)mod\ 2==0? a_i:-a_i,\sum pc(i\&1)mod\ 2==0? a_i:-a_i,\sum pc(i\&2)mod\ 2==0? a_i:-a_i···\sum pc(i\&(n-1))mod\ 2==0? a_i:-a_i)*(\sum pc(i\&0)mod\ 2==0? b_i:-b_i,\sum pc(i\&1)mod\ 2==0? b_i:-b_i,\sum pc(i\&2)mod\ 2==0? b_i:-b_i···\sum pc(i\&(n-1))mod\ 2==0? b_i:-b_i)\\ &=((\sum pc(i\&0)mod\ 2==0? a_i:-a_i)*(\sum pc(j\&0)mod\ 2==0? b_j:-b_j),(\sum pc(i\&1)mod\ 2==0? a_i:-a_i)*(\sum pc(j\&1)mod\ 2==0? b_j:-b_j),(\sum pc(i\&2)mod\ 2==0? a_i:-a_i)*(\sum pc(j\&2)mod\ 2==0? b_j:-b_j)···(\sum pc(i\&(n-1))mod\ 2==0? a_i:-a_i)*(\sum pc(j\&(n-1))mod\ 2==0? b_j:-b_j))\\ &=(\sum pc((i\oplus j)\&0)mod\ 2==0? a_i*b_j:-a_i*b_j,\sum pc((i\oplus j)\&1)mod\ 2==0? a_i*b_j:-a_i*b_j,\sum pc((i\oplus j)\&2)mod\ 2==0? a_i*b_j:-a_i*b_j···\sum pc((i\oplus j)\&(n-1))mod\ 2==0? a_i*b_j:-a_i*b_j)\\ &=(\sum pc(k\&0)mod\ 2==0?\sum_{i \oplus j=k}a_i*b_j:-\sum_{i \oplus j=k}a_i*b_j,\sum pc(k\&1)mod\ 2==0? \sum_{i \oplus j=k}a_i*b_j:-\sum_{i \oplus j=k}a_i*b_j,\sum pc(k\&2)mod\ 2==0? \sum_{i \oplus j=k}a_i*b_j:-\sum_{i \oplus j=k}a_i*b_j···\sum pc(k\&(n-1))mod\ 2==0? \sum_{i \oplus j=k}a_i*b_j:-\sum_{i \oplus j=k}a_i*b_j)\\ &=FWT(A\oplus B) \end{aligned}
F W T ( A ) ∗ F W T ( B ) = ( ∑ p c ( i & 0 ) m o d 2 = = 0 ? a i : − a i , ∑ p c ( i & 1 ) m o d 2 = = 0 ? a i : − a i , ∑ p c ( i & 2 ) m o d 2 = = 0 ? a i : − a i ⋅ ⋅ ⋅ ∑ p c ( i & ( n − 1 ) ) m o d 2 = = 0 ? a i : − a i ) ∗ ( ∑ p c ( i & 0 ) m o d 2 = = 0 ? b i : − b i , ∑ p c ( i & 1 ) m o d 2 = = 0 ? b i : − b i , ∑ p c ( i & 2 ) m o d 2 = = 0 ? b i : − b i ⋅ ⋅ ⋅ ∑ p c ( i & ( n − 1 ) ) m o d 2 = = 0 ? b i : − b i ) = ( ( ∑ p c ( i & 0 ) m o d 2 = = 0 ? a i : − a i ) ∗ ( ∑ p c ( j & 0 ) m o d 2 = = 0 ? b j : − b j ) , ( ∑ p c ( i & 1 ) m o d 2 = = 0 ? a i : − a i ) ∗ ( ∑ p c ( j & 1 ) m o d 2 = = 0 ? b j : − b j ) , ( ∑ p c ( i & 2 ) m o d 2 = = 0 ? a i : − a i ) ∗ ( ∑ p c ( j & 2 ) m o d 2 = = 0 ? b j : − b j ) ⋅ ⋅ ⋅ ( ∑ p c ( i & ( n − 1 ) ) m o d 2 = = 0 ? a i : − a i ) ∗ ( ∑ p c ( j & ( n − 1 ) ) m o d 2 = = 0 ? b j : − b j ) ) = ( ∑ p c ( ( i ⊕ j ) & 0 ) m o d 2 = = 0 ? a i ∗ b j : − a i ∗ b j , ∑ p c ( ( i ⊕ j ) & 1 ) m o d 2 = = 0 ? a i ∗ b j : − a i ∗ b j , ∑ p c ( ( i ⊕ j ) & 2 ) m o d 2 = = 0 ? a i ∗ b j : − a i ∗ b j ⋅ ⋅ ⋅ ∑ p c ( ( i ⊕ j ) & ( n − 1 ) ) m o d 2 = = 0 ? a i ∗ b j : − a i ∗ b j ) = ( ∑ p c ( k & 0 ) m o d 2 = = 0 ? i ⊕ j = k ∑ a i ∗ b j : − i ⊕ j = k ∑ a i ∗ b j , ∑ p c ( k & 1 ) m o d 2 = = 0 ? i ⊕ j = k ∑ a i ∗ b j : − i ⊕ j = k ∑ a i ∗ b j , ∑ p c ( k & 2 ) m o d 2 = = 0 ? i ⊕ j = k ∑ a i ∗ b j : − i ⊕ j = k ∑ a i ∗ b j ⋅ ⋅ ⋅ ∑ p c ( k & ( n − 1 ) ) m o d 2 = = 0 ? i ⊕ j = k ∑ a i ∗ b j : − i ⊕ j = k ∑ a i ∗ b j ) = F W T ( A ⊕ B ) 这个证明写的我累死了
证完就好了
3.3.2计算
定义
F
W
T
(
A
)
=
{
(
F
W
T
(
A
0
+
A
1
)
,
F
W
T
(
A
0
−
A
1
)
)
(
n
≠
1
)
A
(
n
=
1
)
FWT(A)=\begin{cases} (FWT(A_0+A_1),FWT(A_0-A_1))(n\ne1)\\ A(n=1) \end{cases}
F W T ( A ) = { ( F W T ( A 0 + A 1 ) , F W T ( A 0 − A 1 ) ) ( n ̸ = 1 ) A ( n = 1 ) 我觉得FWT的脑洞真大,为啥这样就好了呢 就让我来解释一下吧 前提条件一样
F
W
T
(
A
+
B
)
=
F
W
T
(
A
)
+
F
W
T
(
B
)
FWT(A+B)=FWT(A)+FWT(B)
F W T ( A + B ) = F W T ( A ) + F W T ( B ) ,通过这个把式子拆开 考虑当前二进制最高位,前
2
k
−
1
2^{k-1}
2 k − 1 项的位置最高位都为0,所以and最高位之后一定不会是1所以
A
0
A_0
A 0 和
A
1
A_1
A 1 的贡献都是原符号,由于后
2
k
−
1
2^{k-1}
2 k − 1 项的位置最高位都为1,所以
A
0
A_0
A 0 的贡献都是原符号,
A
1
A_1
A 1 的贡献符号反号 那么IFWT呢? 推导: 已知
F
W
T
(
A
)
0
FWT(A)_0
F W T ( A ) 0 、
F
W
T
(
A
)
1
FWT(A)_1
F W T ( A ) 1 ,求
A
0
A_0
A 0 、
A
1
A_1
A 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
)
\because FWT(A)_0=FWT(A_0)+FWT(A_1),FWT(A)_1=FWT(A_0)-FWT(A_1)\\ \therefore A_0=IDFT(FWT(A_0))=IDFT(\frac {FWT(A)_0+FWT(A)_1}2),A_1= IDFT(FWT(A_1))=IDFT(\frac {FWT(A)_0-FWT(A)_1}2)
∵ 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 ( 2 F W T ( A ) 0 + F W T ( A ) 1 ) , A 1 = I D F T ( F W T ( A 1 ) ) = I D F T ( 2 F W T ( A ) 0 − F W T ( A ) 1 )
总结:
I
F
W
T
(
A
)
=
{
(
I
F
W
T
(
A
0
)
+
I
F
W
T
(
A
1
)
2
,
I
F
W
T
(
A
0
)
−
I
F
W
T
(
A
1
)
2
)
(
n
≠
1
)
A
(
n
=
1
)
IFWT(A)=\begin{cases} (\frac {IFWT(A_0)+IFWT(A_1)}{2},\frac {IFWT(A_0)-IFWT(A_1)}{2})(n\ne1)\\ A(n=1) \end{cases}
I F W T ( A ) = { ( 2 I F W T ( A 0 ) + I F W T ( A 1 ) , 2 I F W T ( A 0 ) − I F W T ( A 1 ) ) ( n ̸ = 1 ) A ( n = 1 )
代码
inline void FWT ( LL* A, const int fla)
{
for ( rg int i= 1 ; i< lenth; i<<= 1 )
for ( rg int j= 0 ; j< lenth; j+ = ( i<< 1 ) )
for ( rg int k= 0 ; k< i; k++ )
{
const int x= A[ j+ k] , y= A[ j+ k+ i] ;
A[ j+ k] = x+ y;
A[ j+ k+ i] = x- y;
if ( fla== - 1 ) A[ j+ k] / = 2 , A[ j+ k+ i] / = 2 ;
}
}
然后好像还有个优化,在一定条件下可以使用,就是把除法留到最后除,代码:
inline void FWT ( LL* A, const int fla)
{
for ( rg int i= 1 ; i< lenth; i<<= 1 )
for ( rg int j= 0 ; j< lenth; j+ = ( i<< 1 ) )
for ( rg int k= 0 ; k< i; k++ )
{
const int x= A[ j+ k] , y= A[ j+ k+ i] ;
A[ j+ k] = x+ y;
A[ j+ k+ i] = x- y;
}
if ( fla== - 1 )
for ( rg int i= 0 ; i< lenth; i++ )
A[ i] / = lenth;
}
这就是xor的FWT啦
4总结
这个FWT写了好久,终于完结了,其实FWT本身代码并不长,关键在于理解。FWT用到的地方没FFT多,但依然值得学一下,拓宽思路 相关的题? 例题1(by update): NowCoder 295-H 题意,给出n个数(
n
≤
500000
,
a
i
≤
500000
n\leq500000,a_i\leq500000
n ≤ 5 0 0 0 0 0 , a i ≤ 5 0 0 0 0 0 ),要求选出最少的数使异或值为所有数的异或值 解法,用0/1代表x值是否能取到,使用FWT异或卷积,容易发现最多做log次,每一次推复杂度
O
(
n
)
O(n)
O ( n ) ,做IDFT时由于只要求一个值,所以复杂度
O
(
n
)
O(n)
O ( n ) ,总复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O ( n l o g n ) 代码:
#include <cstdio>
#include <cctype>
#include <algorithm>
#define rg register
typedef long long LL;
template < typename T> inline T max ( const T a, const T b) { return a> b? a: b; }
template < typename T> inline T min ( const T a, const T b) { return a< b? a: b; }
template < typename T> inline void mind ( T& a, const T b) { a= a< b? a: b; }
template < typename T> inline void maxd ( T& a, const T b) { a= a> b? a: b; }
template < typename T> inline T abs ( const T a) { return a> 0 ? a: - a; }
template < typename T> inline void swap ( T& a, T& b) { T c= a; a= b; b= c; }
template < typename T> inline T gcd ( const T a, const T b) { if ( ! b) return a; return gcd ( b, a% b) ; }
template < typename T> inline T lcm ( const T a, const T b) { return a/ gcd ( a, b) * b; }
template < typename T> inline T square ( const T x) { return x* x; } ;
template < typename T> inline void read ( T& x)
{
char cu= getchar ( ) ; x= 0 ; bool fla= 0 ;
while ( ! isdigit ( cu) ) { if ( cu== '-' ) fla= 1 ; cu= getchar ( ) ; }
while ( isdigit ( cu) ) x= x* 10 + cu- '0' , cu= getchar ( ) ;
if ( fla) x= - x;
}
template < typename T> inline void printe ( const T x)
{
if ( x>= 10 ) printe ( x/ 10 ) ;
putchar ( x% 10 + '0' ) ;
}
template < typename T> inline void print ( const T x)
{
if ( x< 0 ) putchar ( '-' ) , printe ( - x) ;
else printe ( x) ;
}
const int mod= 998244353 , lenth= 524288 ;
int n, a[ lenth] , pc[ lenth] , val, f[ lenth] ;
inline void FWT ( int * A)
{
for ( rg int i= 1 ; i< lenth; i<<= 1 )
for ( rg int j= 0 ; j< lenth; j+ = i<< 1 )
for ( rg int k= 0 ; k< i; k++ )
{
const int x= A[ j+ k] , y= A[ j+ k+ i] ;
A[ j+ k] = ( x+ y) % mod;
A[ j+ k+ i] = ( x+ mod- y) % mod;
}
}
int main ( )
{
read ( n) ;
for ( rg int i= 1 , x; i<= n; i++ ) read ( x) , a[ i] = 1 , val^ = x;
a[ 0 ] = 1 ;
FWT ( a) ;
for ( rg int i= 1 ; i< lenth; i++ ) pc[ i] = pc[ i^ ( i& - i) ] + 1 ;
for ( rg int i= 0 ; i< lenth; i++ ) f[ i] = 1 ;
for ( rg int tim= 0 ; tim<= 19 ; tim++ )
{
LL calc= 0 ;
for ( rg int i= 0 ; i< lenth; i++ ) calc+ = ( pc[ i& val] & 1 ) ? - f[ i] : f[ i] ;
calc% = mod;
if ( calc)
{
print ( n- tim) ;
return 0 ;
}
for ( rg int i= 0 ; i< lenth; i++ ) f[ i] = ( LL) f[ i] * a[ i] % mod;
}
return 0 ;
}
例题2(by update): 我的博客:CF 453 D 撒花结束! 由于写这篇博客写的匆忙,并且很多东西是自己推的,所以如果发现有误请及时提醒我哦