遗憾的是 math 里面一直没有很好的讲这个东西……所以这次细致说说。

FWT 的本质

类似于多项式卷积中,利用 ntt 变换使得卷积 \(\to\) 点乘,fwt 也是类似的应用。

定义某种位运算 \(\oplus\),那么 fwt 处理的位运算卷积形如:

\[H = F * G \implies H_k = \sum_{i \oplus j = k} F_i G_j
\]

那么我们需要构造出一种变换,使得:

\[H = F * G \iff fwt(H) = fwt(F) \cdot fwt(G)
\]

暂时我们还不得而知如何变换,考虑设 \(c(i, j)\) 表示变换系数,那么有:

\[fwt(F)_i = \sum c(i, j) F_j
\]

那么对应的点积:

\[fwt(H)_k = \sum_i \sum_j c(k, i) F_i c(k, j) G_j = \sum_i c(k, i) H_i
\]

根据卷积定义:

\[\sum_i c(k, i) H_i = \sum_i c(k, i) \sum_{x \oplus y = i} F_x G_y = \sum_x \sum_y F_x G_y c(k, x \oplus y)
\]

对比:

\[\sum_x \sum_y F_x G_y c(k, x \oplus y) = \sum_i \sum_j c(k, i) F_i c(k, j) G_j
\]

我们可以得知:

\[c(k, x \oplus y) = c(k, x) c(k, y)
\]

这个等式便是 fwt 的核心。

另外,考虑到位运算每一位是独立的,那么 \(c(x, y)\) 非常重要的性质是可以按位考虑。也就是说:

\[c(i, j) = c(i_0, j_0) c(i_1, j_1) \cdots
\]

其中 \(i_k\) 表示 \(i\) 的第 \(k\) 位。

那么我们只需要构造出 \(c(0/1, 0/1)\) 即可。

不妨假设我们已经构造出了 \(c\),那么怎么求解呢?

类似 ntt 的考虑,分治:

\[fwt_i = \sum c(i, j) F_j = \sum_{j = 0}^{(n / 2) - 1} c(i, j) F_j + \sum_{j = n / 2}^{n - 1} c(i, j) F_j
\]

将最高位拆出来,分别记为 \(i', j'\):

\[fwt_i = c(i_0, 0) \sum_{j = 0}^{(n / 2) - 1} c(i, j) F_j + c(i_0, 1) \sum_{j = n / 2}^{n - 1} c(i, j) F_j
\]

于是分半之后:

\[fwt(F)_i = c(i_0, 0) fwt(F_0)_i + c(i_0, 1) fwt(F_1)_i
\]

于是可以 \(O(n)\) 的合并两个规模减半的东西了,于是总复杂度 \(O(w 2^w)\),其中 \(w\) 是位数。

对于逆变换,将 \(c\) 求个逆,变换回去即可。

FWT 的构造

现在我们对于 \(\texttt{or, and, xor}\) 尝试构造其 \(c\) 矩阵。

\(\texttt{or}\)

首先,注意到 \(c(0, 0) c(0, 0) = c(0, 0 | 0)\),于是 \(c(0, 0) = 0/1\)。

同理,不难得出 \(c(0/1, 0/1) \in \{0, 1\}\)。

考虑 \(c(0, 0) c(0, 1) = c(0, 1)\) 可以得出 \(c(0, 0) = c(0, 1) = 1\) 或者 \(c(0, 1) = 0\)。

同理考虑 \(c(1, 0) c(1, 1) = c(1, 1)\) 也可以知道 \(c(1, 1) = 0\) 或者 \(c(1, 0) = c(1, 1) = 1\)。

注意到需要构造出的矩阵有逆,那么只能是:

\[\begin{bmatrix}
1 & 1 \\ 1 & 0
\end{bmatrix} \text{或者}
\begin{bmatrix}
1 & 0 \\ 1 & 1
\end{bmatrix}
\]

值得注意的是,第二种矩阵 \(c(i, j)\) 对应的等式为 \([i \& j = j]\),也就是说:

\[fwt_i = \sum_{i \& j = j} F_j = \sum_{j \subseteq i} F_j
\]

相当于子集求和!

void fwtor(int n, int inv = {1, -1}) {
for (int u = 2, k = 1; u <= n; u <<= 1, k <<= 1)
for (int i = 0; i < n; i += u)
for (int j = 0; j < k; ++j)
fwt[i + j + k] += fwt[i + j] * inv;
}

\(\texttt{and}\)

首先还是注意到 \(c(0/1, 0/1) \in \{0, 1\}\)。

考虑 \(c(0, 0) c(0, 1) = c(0, 0)\) 得出 \(c(0, 0) = 0\) 或者 \(c(0, 0) = c(0, 1) = 1\)。

同理考虑 \(c(1, 0) c(1, 1) = c(1, 0)\) 得出 \(c(1, 0) = 0\) 或者 \(c(1, 0) = c(1, 1) = 1\)。

那么还是:

\[\begin{bmatrix}
1 & 1 \\ 0 & 1
\end{bmatrix} \text{或者}
\begin{bmatrix}
0 & 1 \\ 1 & 1
\end{bmatrix}
\]

值得注意的是,第一种矩阵 \(c(i, j)\) 对应的是 \([i \& j = i]\),也就是说:

\[fwt_i = \sum_{i \& j = j} F_j = \sum_{i \subseteq j} F_j
\]

相当于超集求和!

void fwtand(int n, int inv = {1, -1}) {
for (int u = 2, k = 1; u <= n; u <<= 1, k <<= 1)
for (int i = 0; i < n; i += u)
for (int j = 0; j < k; ++j)
fwt[i + j] += fwt[i + j + k] * inv;
}

\(\texttt{xor}\)

考虑对于任意 \(x, y \in \{0, 1\}\) 存在 \(c(0, 0) c(x, y) = c(x, y)\),那么一定存在 \(c(0, 0) = 1\),否则 \(c(1, 1) = c(1, 0) = 0\) 显然没有逆,不可行。

考虑 \(c(0, 1) c(0, 1) = c(0, 0)\),那么 \(c(0, 1) = \pm 1\)。

\(c(1, 0) c(1, 0) = c(1, 1) c(1, 1) = c(1, 0)\),所以 \(c(1, 0) = 1\),否则 \(c(1, 1) = c(1, 0) = 0\) 则显然没有逆。

\(c(1, 1) c(1, 1) = c(1, 0)\),考虑到 \(c(1, 0) = 1\),那么自然 \(c(1, 1) = \pm 1\)。

所以可行的矩阵为:

\[\begin{bmatrix}
1 & 1 \\ 1 & -1
\end{bmatrix}
\text{或者}
\begin{bmatrix}
1 & -1 \\ 1 & 1
\end{bmatrix}
\]

注意到对于第一个矩阵,实际上的系数为 \((-1)^{|i \& j|}\)。啥也不相当于。

void fwtxor(int n, int inv = {1, 1/2}) {
for (int u = 2, k = 1; u <= n; u <<= 1, k <<= 1)
for (int i = 0; i < n; i += u)
for (int j = 0; j < k; ++j) {
int x = fwt[i + j], y = fwt[i + j + k];
fwt[i + j] = (x + y) * inv, fwt[i + j + k] = (x - y) * inv;
}
}

算法学习笔记(45): 快速沃尔什变换 FWT的更多相关文章

  1. 算法学习笔记(17): 快速傅里叶变换(FFT)

    快速傅里叶变换(FFT) 有趣啊,都已经到NOI的难度了,救命 首先,我们先讲述一下前置知识.已经明白的读者请移步后文 虚数 定义:\(z = a + bi\),其中 \(a, b \in R\ \ ...

  2. 一个数学不好的菜鸡的快速沃尔什变换(FWT)学习笔记

    一个数学不好的菜鸡的快速沃尔什变换(FWT)学习笔记 曾经某个下午我以为我会了FWT,结果现在一丁点也想不起来了--看来"学"完新东西不经常做题不写博客,就白学了 = = 我没啥智 ...

  3. 【学习笔鸡】快速沃尔什变换FWT

    [学习笔鸡]快速沃尔什变换FWT OR的FWT 快速解决: \[ C[i]=\sum_{j|k=i} A[j]B[k] \] FWT使得我们 \[ FWT(C)=FWT(A)*FWT(B) \] 其中 ...

  4. 快速沃尔什变换FWT

    快速沃尔什变换\(FWT\) 是一种可以快速完成集合卷积的算法. 什么是集合卷积啊? 集合卷积就是在集合运算下的卷积.比如一般而言我们算的卷积都是\(C_i=\sum_{j+k=i}A_j*B_k\) ...

  5. 集合并卷积的三种求法(分治乘法,快速莫比乌斯变换(FMT),快速沃尔什变换(FWT))

    也许更好的阅读体验 本文主要内容是对武汉市第二中学吕凯风同学的论文<集合幂级数的性质与应用及其快速算法>的理解 定义 集合幂级数 为了更方便的研究集合的卷积,引入集合幂级数的概念 集合幂级 ...

  6. Johnson算法学习笔记

    \(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...

  7. 算法学习笔记(3): 倍增与ST算法

    倍增 目录 倍增 查找 洛谷P2249 重点 变式练习 快速幂 ST表 扩展 - 运算 扩展 - 区间 变式答案 倍增,字面意思即"成倍增长" 他与二分十分类似,都是基于" ...

  8. Miller-Rabin 与 Pollard-Rho 算法学习笔记

    前言 Miller-Rabin 算法用于判断一个数 \(p\) 是否是质数,若选定 \(w\) 个数进行判断,那么正确率约是 \(1-\frac{1}{4^w}\) ,时间复杂度为 \(O(\log ...

  9. 算法学习笔记(9): 中国剩余定理(CRT)以及其扩展(EXCRT)

    扩展中国剩余定理 讲解扩展之前,我们先叙述一下普通的中国剩余定理 中国剩余定理 中国剩余定理通过一种非常精巧的构造求出了一个可行解 但是毕竟是构造,所以相对较复杂 \[\begin{cases} x ...

  10. 算法学习笔记(20): AC自动机

    AC自动机 前置知识: 字典树:可以参考我的另一篇文章 算法学习笔记(15): Trie(字典树) KMP:可以参考 KMP - Ricky2007,但是不理解KMP算法并不会对这个算法的理解产生影响 ...

随机推荐

  1. Oracle 一些触发器自治事务相关错误

    Oracle 一些触发器自治事务相关错误 table XXX is mutating,trigger/function may not see it 在触发器中调用的函数或者语句有查询当前表的操作,比 ...

  2. 第 8章 Python 爬虫框架 Scrapy(下)

    第 8章 Python 爬虫框架 Scrapy(下) 8.1 Scrapy 对接 Selenium 有一种反爬虫策略就是通过 JS 动态加载数据,应对这种策略的两种方法如下:  分析 Ajax 请求 ...

  3. 使用日志上下文聚合插件使能上下文查询及Livetail

    简介: 日志上下文浏览是排查业务故障时常用的方式,但受限于Logtail插件系统的设计,在Logtail 1.2.1版本前,如果用户使用Logtail插件来处理日志或采集容器的标准输出,那么用户将无法 ...

  4. OceanBase时序数据库CeresDB正式商用 为用户提供安全可靠的数据存储管理服务

    简介: OceanBase完成OLAP和OLTP双重能力并行后,向数据管理领域多模方向迈出第一步. 近日,在数据库OceanBase3.0峰会上,OceanBase CEO杨冰宣布首个时序数据库产品C ...

  5. WPF dotnet 6 开启 PM v2 的 DPI 感知 导致触摸线程访问 UI 属性抛异常

    本文记录一个 WPF 在 dotnet 6 的一个已知问题,且此问题我已修复提交给官方仓库.这是一个只有在 dotnet 6 框架下,非 dotnet 5 也非 .NET Core 3.1 也非 .N ...

  6. 从零开始写 Docker(十二)---实现 mydocker stop 停止容器

    本文为从零开始写 Docker 系列第十二篇,实现类似 docker stop 的功能,使得我们能够停止指定容器. 完整代码见:https://github.com/lixd/mydocker 欢迎 ...

  7. ios系统的css兼容问题处理和iOS上网页滑动不流畅问题

    1.H5网页touch滑动的时候在苹果手机上出现不流畅的问题 -webkit-overflow-scrolling 用来控制元素在移动设备上是否使用滚动回弹效果. 解决办法:给所有网页添加如下样式 b ...

  8. java里面的方法。

    java里面的方法. java方法是语句的组合,他们在一起执行一个功能. 方法是解决一类问题的步骤的有序组合 方法包含于类或对象中 方法在程序中被创建在其他地方被引用 方法类似于其他语言里面的函数 e ...

  9. c语言在Linux中的使用

    gcc版本升级 如何验证gcc正常使用,编译c以及运行 过程 要验证GCC(GNU Compiler Collection)是否正常使用,您可以按照以下步骤进行操作: 检查GCC是否安装:打开终端或命 ...

  10. EDP .Net开发框架--权限

    平台下载地址:https://gitee.com/alwaysinsist/edp 权限介绍 权限实际上就是谁有权使用或是访问什么,这里的"谁"可以视作"授权对象&quo ...