首页 > 其他分享 >FWT 小记

FWT 小记

时间:2023-09-15 23:12:32浏览次数:36  
标签:limits sum FFT lor FWT operatorname 小记

卷积

通用定义:

\[\text{令 } F = G\times H \text{ 。} \\ \text{则有 } f_i=\sum\limits_{x=0}^{n-1}\sum\limits_{y=0}^{n-1}g_x h_y [x\oplus y=i] \]

若 \(\oplus\) 为 \(+\),就是多项式乘法,可以使用 FFT 等手段解决。

当 \(\oplus\) 为 位运算 时,则属于位运算卷积,可用 FWT/FMT 解决。

FWT/FMT

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

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

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

Or

即 \(f[i]=\sum\limits_{x=0}^{n-1}\sum\limits_{y=0}^{n-1}g_x h_y [x\lor y=i]\)。

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

这里我们可以定义 Or 的 FWT 形式为:\(\operatorname{FWT}[F]=\sum\limits_{i=i\lor j}f_j\),即 \(\operatorname{FWT}[F]_i\) 的值为 \(i\) 的子集的位置对应的和。

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

方便起见,同样假设 \(n=2^k\)。

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

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

那么就分为 \(f_0,\cdots,f_n\) 和 \(f_{n},\cdots,f_{2n-1}\) 两部分。

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

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

怎么补上?很简单,\(f_{n+x}+=f_x\) 即可。

逆变换呢?可以发现这就是个高维前缀和,所以做差分即可。

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]/*诺,差分*/);
}

注意我们上面的一切都基于:\(\operatorname{FWT}[F]=\sum\limits_{i=i\lor j}f_j\) 转换后的乘法仍然成立。

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

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

于是有这么一个证明:

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

我们现在要考虑对 \(\operatorname{FWT}[F]\) 是否成立。

\[\begin{alignat}{} \operatorname{FWT}[F]&=\operatorname{FWT}[F_0],\operatorname{FWT}[F_1]+\operatorname{FWT}[F_0] \\ &=\operatorname{FWT}[G_0]\operatorname{FWT}[H_0],\operatorname{FWT}[G_0]\operatorname{FWT}[H_0]+\operatorname{FWT}[G_1]\operatorname{FWT}[H_1]+\operatorname{FWT}[G_1]\operatorname{FWT}[H_0]+\operatorname{FWT}[H_1]\operatorname{FWT}[G_0] \\ &=\operatorname{FWT}[G_0]\operatorname{FWT}[H_0],(\operatorname{FWT}[G_0]+\operatorname{FWT}[G_1])(\operatorname{FWT}[H_0]+\operatorname{FWT}[H_1]) \\ &=(\operatorname{FWT}[G_0],\operatorname{FWT}[G_0]+\operatorname{FWT}[G_1]) (\operatorname{FWT}[H_0],\operatorname{FWT}[H_0]+\operatorname{FWT}[H_1]) \\ &=\operatorname{FWT}[G] \operatorname{FWT}[H] \\ \end{alignat} \]

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

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

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

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

And

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

我们重新定义一下:\(\operatorname{FWT}[F]=\sum\limits_{i=i\land j}f_j\)。

然后类似地套用:

\[\operatorname{FWT}[F]= \begin{cases} F & n=1 \\ F_0+F_1,F_0 & n>1 \\ \end{cases} \]

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

Xor

还不会,咕。

标签:limits,sum,FFT,lor,FWT,operatorname,小记
From: https://www.cnblogs.com/LQ636721/p/17699505.html

相关文章

  • sepolicy进阶小记
    上下文定义标准的label取名方式是需要被遵守的,因为很多宏里面就直接用了。。hwservice_contexts这里标注的是使用hwbinder的服务通信的接口标准的label取名方式是以_hwservice结尾hwbinder是框架与供应商内容之间的ipc通信模块同理,还有个vndbinder,是供应商内容之间的......
  • 线程池------小记
    1、线程池的产生背景1、线程是一种系统资源,每创建一个新的线程都会占用一定的内存。如果是高并发的情况下,短时间生成了很多任务,如果为每个任务都创建一个新的线程,对内存的占用是相当大的,甚至有可能出现内存内存溢出。2、同时线程也不是创建的越多越好,在cpu核数的限制下,当需要大量......
  • docker常用功能小记
    1、查看docker容器、镜像的元数据dockerinspect容器ID/镜像IDdockerinspectimages示例如下:应用:查看容器关于目录挂载的信息:dockerinspectxxxx|grepMounts-A50查看挂载数据Mounts后50行的数据,如下:2、查看容器运行的日志实时查看日志dockerlogs-fcontainer......
  • 「Log」2023.9.7 小记
    序幕\(\text{6:40}\):准时到校,大屏幕好像又抽风自己开了。写题。\(\text{7:13}\):一道优化建图网络流咕了三天,写的CDQ优化建图。\(\color{black}{P5331\[SNOI2019]\通信}\)朴素的建模不难想到,每个基站拆成入与出两点,中间连边,跑DAG最小路径覆盖。这样建边是\(n^2\)的,考虑......
  • 「Log」2023.9.6 小记
    序幕\(\text{6:10}\):闹钟没响,惊醒。\(\text{6:45}\):到校,写题。\(\text{7:30}\):膜你赛。大致浏览,看题目就知道比昨天的难。还是先推一推T1,手玩一下找到性质,写的时候出了一点波澜,注意炸longlong的问题应该切掉了。T2瞅几眼感觉不可做就直接打一个暴力。T3差不多能看出......
  • 「Log」2023.9.5 小记
    序幕\(\text{6:40}\):提早到校,作息调整成功,博客昨晚整完了,直接开始写题。\(\text{7:30}\):题没写完,开始打模拟赛。花\(30mins\)浏览题目,感觉T1是可做题,考虑T1。考虑强连通分量的贡献,本来想从大往小选贪心,发现不一定有解,时空间还算允许索性换成背包。第二个询问猜测存在构......
  • 『算法小记』SAM
    引入  daduoli最近对自己的名字很感兴趣,于是他开始研究自己的名字。知周所众,搞清楚一个字符串的最好方法就是把他的所有子串列出来(误),所以daduoli开始尝试列举他名字中所有的子串。  列了好一会,daduoli发现子串太多了,于是尝试把它们拼在一起。拼了好一会儿,他拼出来一个奇怪的......
  • 每日小记2023.9.1
    内存管理对堆而言的,程序在运行时主动从堆上申请内存,这些内存通过go的内存分配器分配,由垃圾回收器回收。栈是每个goroutine独有的,不需要在操作的时候加锁,而堆上的内存有时需要加锁防止多线程冲突。对程序上的内存回收需要通过标记清除阶段,比如采用三色标记法。对栈而言,他的分配和释......
  • RISCV-MINI cache小记
    该cache映射策略为直接映射,采用写回(writeback)方式。需要注意的细节在于cpu-cache通过mask信号判断访存是读还是写,显然mask全0时为读。下图FSM中省略了dirty会影响状态转移,比如WriteCache到WriteBack,当cache块为dirty时才会触发aw.fire(io.nasti.aw.valid:=is_dirty)。简单解释:......
  • 网络流小记
    从洛谷搬过来并做了些许润色,后面或许还会增加内容(?第一次学的时候似乎忘记写博客了捏网络流全称网络流理论,是把量类比水流的一种模型。最大流基本芝士对于最大流问题,有一种经典的不能在经典的情景:有一个能生产无限水的自来水厂,若干能承载无线水的节点和家三中节点,点与点之间有......