首页 > 编程语言 >算法学习笔记(45): 快速沃尔什变换 FWT

算法学习笔记(45): 快速沃尔什变换 FWT

时间:2024-02-19 20:34:41浏览次数:35  
标签:begin int sum 45 fwt 沃尔什 bmatrix FWT oplus

遗憾的是 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;
			}
}

标签:begin,int,sum,45,fwt,沃尔什,bmatrix,FWT,oplus
From: https://www.cnblogs.com/jeefy/p/18021900

相关文章

  • 代码随想录算法训练营第二十二天|235. 二叉搜索树的最近公共祖先 ● 701.二叉搜索树
    二叉搜索树的最近公共祖先 题目链接:235.二叉搜索树的最近公共祖先-力扣(LeetCode)思路:只要利用二叉搜索树特性,只要当前节点的值位于要求的两个节点之间,就必定是我们要找的节点。最简单的一集。classSolution{public:TreeNode*lowestCommonAncestor(TreeNode*root,......
  • 2045:【例5.13】蛇形填数
    #include<iostream>usingnamespacestd;intmain(){ intn; cin>>n; intb=1,i=0,j=n-1,a[n][n]; for(inti=0;i<n;i++){ for(intj=0;j<n;j++){ a[i][j]=0; } } a[i][j]=1; while(b<n*n){ while(a[i+1][j]==0&&i+1<n){......
  • 代码随想录算法训练营第二十二天 | 450.删除二叉搜索树中的节点, 701.二叉搜索树中的
     450.删除二叉搜索树中的节点 已解答中等 相关标签相关企业 给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。一般来说,删除节点......
  • CMU 15-445(Fall 2023) Project3 Query Execution个人笔记
    Task#1-AccessMethodExecutorsSeqScan算子实现逻辑使用exec_ctx属性获取对应的TableInfo调用MakeIterator方法,获取表的迭代器在Next方法中,每次利用迭代器获得一个满足条件的元组(检查元组是否被删除、元组是否满足filter)Insert算子实现逻辑在Next方法中调用child......
  • P4552 [Poetize6] IncDec Sequence
    先看题目,因为在文中可以发现,它有一个区间加区间减的操作,所以我们想到了线段树和差分,而下面题目是要我们自己查找让所有的数字相同的最小步数。因此我们可以将线段树排除,那么来看差分,对于差分而言,所有的数字都相同,就可以看作对于所有的$2\lei\len$而言,$a_i=0$,最后的结果是......
  • 酷睿i5-12450H+16GB内存!神舟战神Mini电脑1899元到手
    神舟战神Minii5迷你台式电脑正在参与京东年货节大促,搭载酷睿第12代i5-12450H处理器,另外还有16GBDDR4内存和512GBPCIe4.0SSD,整机到手价1899元,应该是目前为止相同配置售价最低的品牌迷你主机。酷睿第12代i5-12450H处理器其实是用于笔记本的型号,拥有超低的功耗但是性能却不低......
  • FWT学习笔记
    FWTFWT即位运算卷积,用来快速计算形如\(\sum\limits_{i\oplusj=k}f_ig_j\),其中\(\oplus\)表示某种位运算。设FWT(A)是幂级数A经过\(\rmFWT\)变换之后得到的幂级数。我们需要令其满足:\(A*B=C\LongleftrightarrowFWT(A)·FWT(B)=FWT(C)\)(点积)。\(\rmFFT\)是......
  • P4559 [JSOI2018] 列队 题解
    题目链接:列队半年前mark的题,结果现在一下子就会做了。顺便写写我的手玩过程和复杂度说明。考虑比较特殊的情况:比较特殊的,发现从黑色到红色区间我们无论咋选择,由于\(\left|a_{right}-a_{left}\right|\),这玩意如果\(right\)表示红色的一边,那么这个绝对值可以直接拆掉,那么......
  • 力扣 145. 二叉树的后序遍历 递归 迭代
    递归/** *Definitionforabinarytreenode. *publicclassTreeNode{ *  intval; *  TreeNodeleft; *  TreeNoderight; *  TreeNode(){} *  TreeNode(intval){this.val=val;} *  TreeNode(intval,TreeNodelef......
  • P4512 【模板】多项式除法
    为什么不能直接用\(F(x)\timesG(x)^{-1}\)做?\(G(x)^{-1}\)是模\(x^{m+1}\)意义下的,\(n-m>m\)时得到的\(Q(x)\)就是错的。记\(F'(x)\)为\(F(x)\)系数翻转后的多项式,即若\(F(x)=\sum\limits_{i=0}^nf_ix^i\),则\(F'(x)=\sum\limits_{i=0}^nf_{n......