FWT 小记

卷积

通用定义:

令 F=G×H 。则有 fi=x=0n1y=0n1gxhy[xy=i]

+,就是多项式乘法,可以使用 FFT 等手段解决。

位运算 时,则属于位运算卷积,可用 FWT/FMT 解决。

FWT/FMT

FWT/FMT 即为 快速沃尔什变换/快速莫比乌斯变换。

这俩玩意儿网上的分类十分不清楚,所以这里也不做区分(以后也许会 upd)。

对于不同的位运算,我们有不同的做法:

Or

f[i]=x=0n1y=0n1gxhy[xy=i]

这里做法类似与 FFT,我们先将其转换为 FWT[F]=FWT[G]FWT[H],然后再通过逆变换 IFWT 弄回去。

这里我们可以定义 Or 的 FWT 形式为:FWT[F]=i=ijfj,即 FWT[F]i 的值为 i 的子集的位置对应的和。

暴力显然没有优化的空间,我们考虑分治。

方便起见,同样假设 n=2k

由于是或运算,所以像 FFT 那样奇偶分组不是很合理。

我们考虑反其道而行之,按最高位分组。

那么就分为 f0,,fnfn,,f2n1 两部分。

分治计算时最高位不被考虑,所以前者相当于钦定了变换后最高位 0,后者则是钦定了最高位 1

前者的答案显然正确,后者的答案则缺少一部分:最高位 0 的子集。

怎么补上?很简单,fn+x+=fx 即可。

逆变换呢?可以发现这就是个高维前缀和,所以做差分即可,复杂度均为 O(nlgn)

Code:

template<bool type,typename _Tp>
void FWT_Or(_Tp *f,int n){
	for(int p=1,l=2;p<n;p=l,l<<=1)
		for(int i=0;i<n;i+=l)
			for(int k=0;k<p;++k) f[i|p|k]=f[i|p|k]+(type?f[i|k]:-f[i|k]/*诺,差分*/);
}

注意我们上面的一切都基于:FWT[F]=i=ijfj 转换后的乘法仍然成立。

但我们并不知道这玩意儿为什么成立……

cmd 大佬的文章用矩阵把这玩意儿手搓了出来,但是我太蒻完全看不懂。

于是有这么一个证明:

假定这个结论对 FWT[F0],FWT[F1] 分别成立,也就是我们分出的两组(最底层只有一个元素时是显然的)。

我们现在要考虑对 FWT[F] 是否成立。

(1)FWT[F]=FWT[F0],FWT[F1]+FWT[F0](2)=FWT[G0]FWT[H0],FWT[G0]FWT[H0]+FWT[G1]FWT[H1]+FWT[G1]FWT[H0]+FWT[H1]FWT[G0](3)=FWT[G0]FWT[H0],(FWT[G0]+FWT[G1])(FWT[H0]+FWT[H1])(4)=(FWT[G0],FWT[G0]+FWT[G1])(FWT[H0],FWT[H0]+FWT[H1])(5)=FWT[G]FWT[H]

归纳法乱搞一下就出来了。

但是第四个式子不是很知道怎么化出来的,挖坑。

然后要进行位运算卷积就类似 FFT 了,先 FWT 化出来点乘再 IFWT 化回去。

值得指出的是这里的 FWT 其实是算的子集和,所以可以拿去优化一些子集问题。

And

有了 Or 打底,And 其实非常容易:

我们重新定义一下:FWT[F]=i=ijfj

然后类似地套用:

FWT[F]={Fn=1F0+F1,F0n>1

证明之类的同上,这玩意儿就是个高维后缀和。

Xor

还不会,咕。

运算扩展

不难发现位运算时可以被扩展到 k 进制的,分别是:minmax 和带模不进位加法。

分别对应到:

Or 的扩展

不难发现就是高位前缀和的每一维多了几个不同的值。

那么就是把这个前缀和做完就行了,复杂度 O(knlgn)

And 的扩展

后缀和做完,完事儿。

不得不说同样的算法,不同的理解方式在不同的部分可以有不同的收获啊。

Xor 的扩展

不会,咕。

posted @   LQ636721  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示