本文是我重温集合幂级数自己思考得到的一些鄙见。
总所周知,DFT 是在做
1 位的
2k 进制数的不进位加法卷积。
FWT 是在做
n 位的
2 进制数的不进位加法卷积。
考虑拓展到
n 位
k 进制数的半加循环卷积。
分析 DFT 的本质,乘范德蒙德矩阵,利用单位根实现循环卷积。
分析 FWT 的本质,插值和逆插值。(看到文末会发现这种理解是浅显的)
k-FWT
二进制下的 FWT 依靠这个式子:
[S=∅]=2n1T⊆U∑(−1)∣S∩T∣
证明不难,略过。
接下来我们把
n 位
k 进制数视作
n 维向量,每一位
vi∈[0,k)。
怎么直接由集合拓展上面的式子到向量?
∅ 实际上是
0 向量。
2n 实际上是枚举所有向量产生的系数,所以是
kn。
∣S∩T∣=∑i=0nSiTi,也就是向量内积。
那
−1 呢,就是
ω21=ωk1。
猜测:
[S=0]=kn1T∑ωk∑iSiTi
证明:
当
S=0,求和始终为
ωk0=1,显然正确。
否则考察
Sp=0,变形原式。
[S=0]=kn1T∑ωk∑iSiTi=kn1T∑i∏ωkSiTi
我们把
T 除了第
p 位,其余位都相同的
T 分为一类。直接枚举
n−1 维向量
T′,再考虑
Tp=j。
[S=0]=kn1T∑i∏ωkSiTi=kn1T′∑j=0∑k−1i=0∏nωkSiTi=kn1T′∑(j=0∑k−1ωkSpj)i=p∏ωkSiTi=kn1T′∑ωkSp−1ωkSpk−1i=p∏ωkSiTi=0
(等比数列变形利用了
Sp=0⇒ωkSp=1)
证毕。
根据这个性质,记
f 是“向量幂级数”,理所当然的有它的沃尔什变换。
f^S=T∑ωk∑iSiTifT
以及逆变换。
fS=kn1T∑ωk∑iSiTif^T
然后你的半加循环卷积理论上来讲就可以直接在沃尔什变换后的“向量幂级数”上点乘,最后逆变换回去。
2-FWT
那原理是什么呢?
回顾集合幂级数的 FWT,找共通处类比。
一个集合幂级数
f=∑SfSxS。
有一种表达方式是令
xS=∑i∈Sxi。
那么 FWT 一种理解方式是,对于一个集合
S,我们定义特征向量
v(S)=((−1)[1∈S],(−1)[2∈S],⋯,(−1)[n∈S])。即
v(S)i=(−1)[i∈S]。
然后对于每个集合,我们把每个元
xi=v(S)i 代入这个
n 元多项式求值,并把求值结果记作
f^S。
你会发现
fT 对
f^S 的贡献系数恰好是
(−1)∣S∩T∣。
所以 FWT 可以理解为代入特征向量插值。
又为什么是这个特征向量呢?
发现
(−1)x⋅(−1)y=(−1)(x+y)mod2=(−1)x⊕y
⊕ 是
k 进制数半加。这里是
2 进制。
联系我们每一位的贡献独立,这个性质实际上是在指数上实现了
1 位
2 进制数的半加。
倘若对
n 位都附上权,就能实现
n 位的半加。
每一位是
v(S)i=(−1)[i∈S]=(−1)Si,于是
v(S)i⋅v(T)i=(−1)Si⋅(−1)Ti=(−1)Si⊕Ti=v(S⊕T)i。
用占位符的乘法描述出来就是:
xS⋅xT=(∏i∈Sxi)(∏i∈Txi)=∏xiSi+Ti=∏xiSi⊕Ti=xS⊕T。
(第二个等号到第三个等号利用了
xi 是
−1 的幂)
经过 FWT 的插值后,
S 和
T 的系数卷积恰好贡献到
S⊕T。
k-FWT 原理
确保透彻理解上述内容后,开始拓展。
第一步,如何将集合幂级数拓展为“向量幂级数”?
很简单,集合幂级数时
xS=∏i∈Sxi。
实际上是
xS=∏xiSi,那你类似的拓展,让单个元指数的范围扩到
[0,k−1]。
这样向量幂级数可以被描述为
n 元
k 次多项式(每一个元是
[0,k−1] 次)。它包含了
kn 项,每一项能与每一个
n 位
k 进制数一一对应。
第二步,如何延用特征向量,以满足
xS⋅xT=xS⊕T?
k 进制半加就是
modk 意义下的循环卷积。
2 进制我们使用
(−1) 的幂来在指数上实现
mod2。
同样的,我们使用
k 次单位根安排特征向量,令
v(S)i=ωkSi。
因为
ωkx⋅ωky=ωkx+ymodk,所以:
xS⋅xT=∏xSi+Timodk=xS⊕T。
于是成立,用这样的特征向量插值是正确的。
回顾前面那个式子:
f^S=T∑ωk∑iSiTifT
当你代入
v(S) 插值时,第
T 项的系数贡献?
fTxT=fT∏xiTi=fT∏v(S)iTi=fT∏ωkSiTi
我们用更本质的做法推导出了
k 进制下的沃尔什变换。
实现
实现上呢,你对每一位贡献系数单独计算(增量法),就是利用下面这个式子:
f^S=T′∑(j=0∑k−1ωkSpj)i=p∏ωkSiTifT
按上面这个式子直接做,分析一下时间复杂度应该是
O(nkn+1)。会这个结合一点分圆多项式的知识就能去水掉 CF1103E Radix sum。
但你发现对于一个
p 不是实际上时按
T′ 分类,然后一类里乘范德蒙德矩阵,线性变换得到
f^S 吗?
所以照搬个 DFT 过来把范德蒙德矩阵那部分从
O(k2) 降到
O(klogk)。
所以 FWT 又有一种理解是对每个位都做一次 DFT。这又能解释为什么 FWT 是插值了。总有一种所学知识又串联起来,大道至简的感觉。
总时间复杂度做到
O(nknlogk),也是我会的最优时间复杂度。不知道能不能更优。
单位根牛逼,点值表示牛逼。
线性代数牛逼,虽然我不会。