遗憾的是 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. 文件上传之Webshell连接方法

    "感谢您阅读本篇博客!如果您觉得本文对您有所帮助或启发,请不吝点赞和分享给更多的朋友.您的支持是我持续创作的动力,也欢迎留言交流,让我们一起探讨技术,共同成长!谢谢!" Websh ...

  2. steam社区留言红小作文模板

    steam社区留言红小作文模板 Dear steam: Im a steam user which most play csgo.i saw i had be banned in steam comm ...

  3. 同为博客,不同风格 ——Hexo另类搭建

    ​简介:通过阿里云云开发平台快速由Hexo创建赛博朋克风格的博客. 一  .通过云开发平台快速创建初始化应用 1.创建相关应用模版请参考链接:Hexo博客框架-轻量.一令部署 2.完成创建后就可以在g ...

  4. [FAQ] Win10 键盘输入的数字英文字体变宽, 胖英文, 如何处理

    输入法 点击右键,找到设置,点击进入. 开启 "全/半角切换" 快捷键为 "Shift + 空格",随后可以使用这个快捷键进行切换正常. Link:https: ...

  5. WPF 给 Pen 的 DashStyle 设置 0 0 的虚线数组将会让渲染线程消耗大量 CPU 资源

    给 WPF 的 Pen 的 DashStyle 属性设置 0 0 的虚线,在绘制几何图形时,绘制的几何图形的尺寸将关联渲染线程所使用的 CPU 资源.大约在周长大于 500 时,将可以从任务管理器上看 ...

  6. 如何参与 .NET 的开发和设计

    现在 dotnet 属于 dotnet 基金会,所有开发者都可以向 dotnet 贡献代码和参与 .NET 的设计,参与路线决策.本文来告诉大家一些基本玩法,带着小伙伴们入坑 注意哦,参与 dotne ...

  7. C# 获取指定文件夹中所有的文件(包括子文件夹的文件)

    有个需求中需要播放指定路径的声音,但你必须要有该路径的声音才可以播放,如果没有该文件则播放默认的声音,该方法用于初始化应用的时候获取指定目录的所有文件,便于后来播放声音的时判断路径是否存在. usin ...

  8. await this.$nextTick()和this.$nextTick(callback)有什么区别?记一次bug调试

    背景 需要实现一个需求,一个小区业务详情页面,在左侧菜单栏切换了小区后,详情页跟着切换. 这个详情页面是根据url上的/:id来确定小区id的,所以切换了小区后,应该切换路由. 于是这样实现: wat ...

  9. 使用qemu运行risc-v ubuntu

    参考 Ubuntu installation on a RISC-V virtual machine using a server install image and QEMU 用到的文件 fw_ju ...

  10. 羽夏壳世界—— PE 解析的实现

    写在前面   此系列是本人一个字一个字码出来的,包括代码实现和效果截图. 如有好的建议,欢迎反馈.码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作.如想转载,请把我的转载信息附在文章后 ...