0%

快速沃尔什变换

还是逃不掉多项式啊


快速沃尔什变换

对于一个位运算的卷积,即形式为$c_i=\Sigma a_j b_k [i==g(j,k)]$的求和,一般最简单最暴力的做法是遍历求和。

对于一个映射$f$,有

即找到一种变换,使得能将卷积等效为点乘,并且确定这个变换的逆变换,就可以用这个方法实现卷积。

数组点乘的复杂度是线性的,而遍历一个数组也至少是线性的,这个过程的主要复杂度就在变换和逆变换中。如果能找到一个优化的方法求出映射$f$与逆映射$f^{-1}$,就可以对卷积进行优化。


or卷积

卷积$c_i=\Sigma a_j b_k [i==(j|k)]$,可以发现对$c_i$有共献的下标$j,k$一定是$c_i$在二进制下的子集。

记$f(a_i)$是$A$中下标$i$的子集之和,求$f(A)$就变成了子集枚举问题。同样,如果要求逆,对$f(a_i)$做子集容斥就能得到$a_i$。

如果暴力去枚举子集,那和$n^2$暴力没什么区别。考虑用位运算子集的性质进行加速。最典型想法的就是fft中的奇偶分治,这里也可以套用。

$A\rightarrow f(A)$的过程是一个典型的折半分治,用沃尔什变换处理or卷积的时间复杂度是$O(nlogn)$的。

代码实现:


and卷积

卷积$c_i=\Sigma a_j b_k [i==(j\&k)]$,可以发现对$c_i$有共献的下标$j,k$一定是$c_i$在二进制下的超集。

同样的思路,记$f(a_i)$是$A$中下标$i$的超集之和,求$f(A)$就变成了补集枚举问题,本质上也是一个子集枚举。用沃尔什变换处理and卷积的时间复杂度也是$O(nlogn)$的。这个和or卷积写法都差不多

代码实现:


xor卷积

卷积$c_i=\Sigma a_j b_k [i==(j\oplus k)]$。异或不能像与和或那样简单地用子集关系表示,需要挖掘其他的性质。

考虑异或整体后的结果,似乎看不出来什么规律。拆位来看,若$i,j,k$表示当前bit的状态,则有$(i\&j)\oplus(i\&k)=i\&(j\oplus k)$,即位运算的分配律。

将这个关系推广到一个整数,同样是成立的。记$i \circ j=popcount(i\&j)\equiv 1 (mod 2)$,即两者与后bit数的奇偶性。存在

记$f(a_i)$是$A$中与下标$i$异或和bit数为偶数减去异或和bit数为奇数的和,即

在这个映射中,$f(a_i)f(b_i)$相乘后,套用上述性质,发现$f(c_i)$符合性质。

这个东西更像fft了,也可以用蝴蝶操作来优化。逆运算也同fft。异或卷积的时间复杂度是$O(nlogn)$级别的。

代码实现:


xnor卷积

卷积$c_i=\Sigma a_j b_k [i==(j xnor k)]$。同或是异或的对偶运算,当两者相同时取1。

同或也具有类似上述的性质,可以使用相同的思路来做,代码也是差不多的。

代码实现:


例题

暂时鸽了(