Fast Walsh-Hadamard Transform——快速沃尔什变换

模板题:

  给定$n = 2^k$和两个序列$A_{0..n-1}$, $B_{0..n-1}$,求

  $$C_i = \sum_{j \oplus k = i} A_j B_k$$

  其中$\oplus$是某一满足交换律的位运算,要求复杂度$O(nlogn)$。



快速沃尔什变换:

  这是什么东西?有用吗?请参阅SDOI2017r2d1-cut。

  看到这个大家是不是立刻想到了快速傅里叶变换?

  $$C_i = \sum_{j + k = i} A_j B_k$$

  我们来想想离散傅里叶变换的本质。

  $$\begin{aligned}& DFT(A)_i \\
  &= A(\omega_n^i)\\
  &=\sum_{j = 1}^n A_j * (\omega_n^i)^j\end{aligned}$$

  令$f(n, i, j) = (\omega_n^i)^j$,则

  $$DFT(A)_i = \sum_{j = 1}^n A_j f(n, i, j)$$

  它要满足$DFT(A)_i * DFT(B)_i = DFT(C)_i$,即

  $$(\sum_{j = 1}^n A_j f(n, i, j))(\sum_{k = 1}^n B_k f(n, i, k))=\sum_{l = 1}^n C_l f(n, i, l)$$

  $$\sum_{j = 1}^n \sum_{k = 1}^n A_j B_k f(n, i, j) f(n, i, k))=\sum_{l = 1}^n (\sum_{a+b=l} A_a B_b) f(n, i, l)$$

  这时我们发现左右分别有$n^2$项,令对应项系数相等,得

  $$f(n, i, j)f(n, i, k) = f(n, i, j + k)$$

  只要任意一个可以进行逆变换且满足上述条件的$f$都可以。

  现在我们把上面的$+$都改成$\oplus$,就是离散沃尔什变换即

  $$DWT(A)_i = \sum_{j = 1}^n A_j f(n, i, j)$$

  $$f(n, i, j)f(n, i, k) = f(n, i, j \oplus k)$$

  怎么样,是不是云里雾里顿开茅塞?

  然而我们还需要变快,所以快速傅里叶变换采用

  $$f(n, i, j) = (\omega_n^i)^j$$

  那它有什么优美的性质呢?

  我们发现, 由于有折半引理,$f(n, i, j)$和$f(n, i+n/2, j)$可以同时从$f(n/2,i,j)$得来。

  那么,从感性的角度,既然$\oplus$是一个位运算,那么应该更容易找到一个跟位运算有关的$f$,这样就自然有类似折半引理的东西使得我们可以做到上述事情。

  例如,当$\oplus$是位与时,可以取$f(i, j) = [i \& j = i]$, 即$j$的二进制完全包含在$i$的二进制里时为1,否则为0。

  当$\oplus$是位异或时, 可取$f(i, j) = (-1)^{count(i \& j)}$,其中$count(x)$表示$x$的二进制表示中1的个数。



逆变换:

  逆变换看上去好难啊。。。

  其实逆变换还是比较简单的。因为既然$f$跟位运算有关,我就只需要考虑某一位就好了。

  例如$\oplus$是位异或时我考虑$n=2,A=(a_0, a_1)$,

  那么$DWT(A) = (da_0 = a_0 + a_1, da_1 = a_0 - a_1)$

  我只需要解一个二元一次方程(把$da_0, da_1$作为常数, $a_0, a_1$作为变量)就可以解出$a_0, a_1$了。

  没了。



关于$f$函数的构造:

  $f$函数怎么构造。。。和逆变换的方法差不多啊。。。只需要看$n=2$的情况就行(实际上一般就是$-1$的几次幂,或者$0, 1, -1$)

  如果记忆力好可以把所有都背下来,反正满足交换律的位运算只有8个。。。

  列一些出来吧。。。(下列$f$函数均将第一个参数$n$省略, $[expr]$在布尔表达式$expr$为真时为1, 否则为假)

  $\oplus$为位与: $f(i, j) = [j \& i = i]$.

  $\oplus$为位或: $f(i, j) = [j \& i = j]$.

  $\oplus$为位异或: $f(i, j) = (-1)^{count(i \& j)}$.

  $\oplus$为位与非,位或非的时候把三个数组的下标都取反就对应位或和位与。

  $\oplus$为同或时直接求位异或卷积再把$C$的下标取反就行了。



吐槽:

  明明可以感性的理解我偏要说这么多。。。

  只是因为闲的慌。。。

  当然是要帮助大家更好的理解FWT。

  至于为什么要满足交换律。。。我才不会告诉你我还没有搞出不满足怎么做。

  有同学说FWT难以感性理解。。。我也不知道如何感性理解。。。

  代码嘛。。。直接拿FFT改一改就好了。。。

时间: 2024-10-12 18:52:04

Fast Walsh-Hadamard Transform——快速沃尔什变换的相关文章

Fast Radial Symmetry Transform/快速径向对称变换

本文主要介绍一下利用径向变换进行特征提取的方法和原理,基本原理主要来自Gareth Loy and Alexander Zelinsky的A Fast Radial Symmetry Transform for Detecting Points of Interest一文.需要原文的可以留下邮箱. Radial Symmetry Transform(径向对称变换)在某种程度上类似于霍夫圆变换,二者的主要区别在于:前者主要考察一副图像中的每个像素点对它周围邻域内的像素点的作用(贡献),而后者则主要

hdu 4965 Fast Matrix Calculation(矩阵快速幂)

题目链接:hdu 4965 Fast Matrix Calculation 题目大意:给定两个矩阵A,B,分别为N*K和K*N: 矩阵C = A*B 矩阵M=CN?N 将矩阵M中的所有元素取模6,得到新矩阵M' 计算矩阵M'中所有元素的和 解题思路:因为矩阵C为N*N的矩阵,N最大为1000,就算用快速幂也超时,但是因为C = A*B, 所以CN?N=ABAB-AB=AC′N?N?1B,C' = B*A, 为K*K的矩阵,K最大为6,完全可以接受. #include <cstdio> #inc

Codeforces 662C(快速沃尔什变换 FWT)

感觉快速沃尔什变换和快速傅里叶变换有很大的区别啊orz 不是很明白为什么位运算也可以叫做卷积(或许不应该叫卷积吧) 我是看 http://blog.csdn.net/liangzhaoyang1/article/details/52819835 里的快速沃尔什变换 这里说一下自己的理解吧,快速傅里叶变换是计算卷积的,就是∑f(x)*g(n-x)这种 快速沃尔什变换也是计算∑f(x)*g(y) ,但这里是计算所有的满足x^y = n(卷积是计算x+y=n)的和 当然,异或也可以换成&,|这些运算符

HDU 4965 Fast Matrix Calculation (矩阵快速幂取模----矩阵相乘满足结合律)

http://acm.hdu.edu.cn/showproblem.php?pid=4965 利用相乘的可结合性先算B*A,得到6*6的矩阵,利用矩阵快速幂取模即可水过. 1 #include<iostream> 2 #include<stdio.h> 3 #include<iostream> 4 #include<stdio.h> 5 #define N 1010 6 #define M 1010 7 #define K 6 8 using namespa

FWT快速沃尔什变换学习笔记

FWT快速沃尔什变换学习笔记 1.FWT用来干啥啊 回忆一下多项式的卷积\(C_k=\sum_{i+j=k}A_i*B_j\) 我们可以用\(FFT\)来做. 甚至在一些特殊情况下,我们\(C_k=\sum_{i*j=k}A_i*B_j\)也能做(SDOI2015 序列统计). 但是,如果我们把操作符换一下呢? 比如这样? \(C_k=\sum_{i|j=k}A_i*B_j\) \(C_k=\sum_{i\&j=k}A_i*B_j\) \(C_k=\sum_{i\wedge j=k}A_i*B_

Codeforces 662C Binary Table(快速沃尔什变换)

Problem 给定一个n(≤20)*m(≤100 000)的01矩阵,每次操作可以将一行或一列取反. 求最终1的最少个数. Solution 前置技能:快速沃尔什变换(FWT). 观察到n较小,考虑\(O(2^n)\)枚举每一行选或不选. 不妨设f(x)表示行的操作状态为x时(我们可用一个二进制数表示状态),经过各种列操作后所得到的最少的1的个数. 可以\(O(m)\)再扫一遍所有列.但显然T飞了. 定义\(C_j\)表示有多少列的状态为j:\(E_k\)表示对于某一列而言,若它经过各种行操作

快速沃尔什变换

快速沃尔什变换 题目背景 模板题,无背景 题目描述 给定长度为\(2^n\)两个序列\(A,B\),设\(C_i=\sum_{j\oplus k=i}A_jB_k\) 分别当\(\oplus\)是or,and,xor时求出\(C\) 输入输出格式 输入格式: 第一行一个数\(n\). 第二行\(2^n\)个数\(A_0..A_{2^n-1}\) 第三行\(2^n\)个数\(B_0..B_{2^n-1}\) 输出格式: 三行每行\(2^n\)个数,分别代表\(\oplus\)是or,and,xor

关于快速沃尔什变换(FWT)的一些个人理解

定义 FWT是一种快速完成集合卷积运算的算法. 它可以用于求解类似C[i]=∑j?k=i A[j]*B[k]的问题. 其中?代表位运算中的|,&,^的其中一种. 求解(正变换) 设F(A)是对于A的一种变换. 并且F(A)要求满足:   F(A)*F(B)=F(A?B) ①  k*F(A)=F(k*A)   ② F(A+B)=F(A)+F(B) ③ (A,B长度相同) 鉴于FWT和FFT长得特别像(而且求解的问题也比较类似),我们可以借鉴一下FFT的思路,采用分治的想法. 首先先把多项式的长度用

快速沃尔什变换与k进制FWT

这是一篇用来卖萌的文章QAQ 考虑以下三类卷积 \(C_k = \sum \limits_{i \;or\;j = k} A_i * B_j\) \(C_k = \sum \limits_{i\;and\;j = k} A_i * B_j\) \(C_k = \sum \limits_{i\;xor\;j = k}A_i * B_j\) 由于前两种可以用FMT(高维前缀和)解决,那我们就谈谈第三种吧 下文中的\(n\)都是形如\(2^i - 1\)的数 下标的开与闭是根据好不好写来定的,但是还是