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

曾经某个下午我以为我会了FWT,结果现在一丁点也想不起来了……看来“学”完新东西不经常做题不写博客,就白学了 = =

我没啥智商 ,网上的FWT博客我大多看不懂,下面这篇博客是留给我我再次忘记FWT时看的,所以像我一样的没智商选手应该也能看懂!有智商选手更能看懂咯!

(写得非常匆忙,如有任何错误请在评论区指正!TAT)

什么是FWT

FWT是用来快速做位运算卷积的。位运算卷积是什么?给出两个数组\(A\)和\(B\)(长度相等且是2的整数次幂),求一个数组\(C\),满足\(A * B = C\),这个“\(*\)”的定义如下:$$A * B = C \Leftrightarrow C_k = \sum_{i\oplus j = k}A_i \cdot B_j$$ 其中“\(\oplus\)”是一种位运算,可以是与(&)、或(|)、异或(^)。

为什么要有一个变换呢?回想一下FFT,FFT求\(A*B\)时(这个“\(*\)”是多项式乘法那个卷积),是把\(A\)和\(B\)各自“变换”了一下,然后把变换后的数组按位相乘,得到“变换后的\(C\)”——\(tf(C)\),然后把\(tf(C)\)逆变换回去,得到\(C\)数组。

FWT做位运算卷积的原理也类似,想要实现快速位运算卷积,就要找到一种变换\(tf\)满足\(tf(A*B) = tf(A)\times tf(B)\),这里的“\(\times\)”表示两个数组按位相乘(和那个表示卷积的“\(*\)”不是一个符号)。

再强调一下本文中符号的定义,在下文中:

\[A * B = C \Leftrightarrow C_k = \sum_{i\oplus j = k}A_i \cdot B_j
\]

\[A \times B = C \Leftrightarrow C_i = A_i \cdot B_i
\]

用FWT解决或卷积

或卷积,就是把\(A * B = C \Leftrightarrow C_k = \sum_{i\oplus j = k}A_i \cdot B_j\)中的“\(\oplus\)”定义为按位或运算(|)。我们的目标是找到一种变换\(tf\)满足\(tf(A*B) = tf(A)\times tf(B)\),还要找到一种逆变换\(utf\),能把\(tf(C)\)变回\(C\)。

目标

  • 找到\(tf\)
  • 找到\(utf\)

找到\(tf\)

这是位运算,所以应该按位分治。

根据下标在最高位是0还是1,把\(A\)数组拆成两个数组\(A_0\)和\(A_1\),\(A_0\)是\(A\)中下标最高位是0的元素组成的数组,\(A_1\)是\(A\)中下标最高位是1的元素组成的数组——实际上,\(A_0\)就是\(A\)的前一半,\(A_1\)是\(A\)的后一半。用\(A = (A_0, A_1)\)表示这种“等式右边两个数组首尾相接就能得到等式左边的数组”的关系。

定义$$tf(A) = (tf(A_0), tf(A_1) + tf(A_0))$$

当\(A\)长度为1,无法再划分时,\(tf(A) = A\)。

对了,显然\(tf(X + Y) = tf(X) + tf(Y)\),这里“\(+\)”就是按位相加。

(这个\(tf\)是怎么找到的?这篇博客讲了讲……但是即使我知道了如何找到或卷积的\(tf\),异或卷积的我还是找不出来……还是甩出这个式子然后证明它吧。)

来证明一下\(tf(C = A * B) = tf(A) \times tf(B)\)。

当\(A, B\)长度均为1时显然。

当\(A, B\)长度大于1时 ,我们使用归纳法——可以假定“长度除以2后\(tf(C = A * B) = tf(A) \times tf(B)\)是成立的”,即$$tf(A_0*B_0) = tf(A_0) \times tf(B_0)\tf(A_1 * B_1) = tf(A_1) \times tf(B_1)\tf(A_0 * B_1) = tf(A_0) \times tf(B_1)\tf(A_1 * B_0) = tf(A_1) \times tf(B_0)$$如果我们在这四个条件的基础上能证明\(tf(C = A * B) = tf(A) \times tf(B)\),则这四个条件递归证明即可,递归到长度为1时,就直接证毕了。

那么如何证明当前这一层\(tf(C = A * B) = tf(A) \times tf(B)\)呢?

首先,$$C=(A_0 * B_0, A_1 * B_0 + A_0 * B_1 + A_1 * B_1)$$。这是可以理解的:在\(A\)中最高位是0的一个下标,和在\(B\)中最高位是0的一个下标,或起来还是0,所以他俩卷积的结果应该放在\(C_0\)中,其余三项同理。

然后从等式左边推一下,$$\begin{align}tf(C) &= (tf(A_0 * B_0), tf(A_1 * B_0 + A_0 * B_1 + A_1 * B_1) + tf(A_0 * B_0))\&=(tf(A_0B_0), tf(A_1B_0) + tf(A_0B_1) + tf(A_1 * B_1) + tf(A_0 * B_0)) \ &= (tf(A_0) \times tf(B_0), tf(A_1) \times tf(B_0) + tf(A_0) \times tf(B_1) + tf(A_1) \times tf(B_1) + tf(A_0)\times tf(B_0))\end{align*}$$

这一步是基于\(tf\)的定义以及上面的那四个条件的。

然后从等式右边推一下,$$\begin{align}tf(A) \times tf(B) &= (tf(A_0), tf(A_1) + tf(A_0)) \times (tf(B_0), tf(B_1) + tf(B_0)))\&=(tf(A_0) \times tf(B_0), tf(A_0)\times tf(B_0) + tf(A_1) \times tf(B_0) + tf(A_0) \times tf(B_1) + tf(A_1) \times tf(B_1))\end{align}$$

这一步是基于“\(\times\)”符号的意义——按位相乘得出来的。

这样一来,等式两边恰好相等诶!

所以我们已经找到了或卷积的\(tf\):$$tf(A) = (tf(A_0), tf(A_1) + tf(A_0))$$

找到\(utf\)

目标:找到一个\(utf\)使得\(utf(tf(A)) = A\)。

这相当于把上面那个式子倒着推,怎么个倒推法呢?

正着推是已知\(A = (A_0, A_1)\),求\(tf(A) = (tf(A)_0, tf(A)_1)\)。

倒着推就是已知\(tf(A) = (tf(A)_0, tf(A)_1)\),求\(utf(tf(A)) = A = (A_0, A_1) = (utf(tf(A_0)), utf(tf(A_1)))\)。

那么根据上面的\(tf(A) = (tf(A_0), tf(A_1) + tf(A_0))\),有\(tf(A)_0 = tf(A_0), tf(A)_1 = tf(A_0) + tf(A_1)\)。

所以直接得到\(tf(A_0) = tf(A)_0\), 两式相减又得到\(tf(A_1) = tf(A)_1 - tf(A)_0\)。

所以\(utf(tf(A)) = A = (A_0, A_1) = (utf(tf(A_0)), utf(tf(A_1)) = (utf(tf(A)_0), utf(tf(A)_1 - tf(A)_0))\)

将\(tf(A)\)替换成\(A\),得到\(utf(A) = (utf(A), utf(A_1) - utf(A_0))\)

这就是逆变换\(utf\)了。

总结

或卷积的FWT:

\[tf(A) = (tf(A_0), tf(A_1) + tf(A_0))
\]

\[utf(A) = (utf(A), utf(A_1) - utf(A_0))
\]

用FWT解决与卷积

与卷积和或卷积非常类似。

有\(C = (A_0*B_0 + A_0*B_1 + A_1 *B_0, A_1*B_1)\)

定义$$tf(A) = (tf(A_0) + tf(A_1), tf(A_1))$$

类似上面或卷积的证明过程可以证明它。

类似地,$$utf(A) = (utf(A_0) - utf(A_1), utf(A_1))$$

用FWT解决异或卷积

和上面的也很类似,但是异或卷积的式子更复杂一丁点。它是:

\[tf(A) = (tf(A_0) + tf(A_1), tf(A_0) - tf(A_1))
\]

\[utf(A) = (\frac{utf(A_0) + utf(A_1)}{2}, \frac{utf(A_0) - utf(A_1)}{2})
\]

证明嘛……和上面的或卷积证明也差不多!

板子

我的异或卷积板子:

  1. ll inc(ll x, ll y){return (x += y) >= P ? x - P : x;}
  2. ll dec(ll x, ll y){return (x -= y) < 0 ? x + P : x;}
  3. void transform(ll *a, int n, bool inv){
  4. for(int l = 2; l <= n; l <<= 1){
  5. int m = l >> 1;
  6. for(ll *p = a; p != a + n; p += l)
  7. for(int i = 0; i < m; i++){
  8. ll t = p[i + m];
  9. p[i + m] = dec(p[i], t);
  10. p[i] = inc(p[i], t);
  11. }
  12. if(inv)
  13. for(int i = 0; i < n; i++)
  14. a[i] = a[i] * inv2 % P;
  15. }
  16. }

异或已经是写起来最长的啦,其他两个都特别短~

一个数学不好的菜鸡的快速沃尔什变换(FWT)学习笔记的更多相关文章

  1. 快速沃尔什变换 FWT 学习笔记【多项式】

    〇.前言 之前看到异或就担心是 FWT,然后才开始想别的. 这次学了 FWT 以后,以后判断应该就很快了吧? 参考资料 FWT 详解 知识点 by neither_nor 集训队论文 2015 集合幂 ...

  2. 快速沃尔什变换 (FWT)学习笔记

    证明均来自xht37 的洛谷博客 作用 在 \(OI\) 中,\(FWT\) 是用于解决对下标进行位运算卷积问题的方法. \(c_{i}=\sum_{i=j \oplus k} a_{j} b_{k} ...

  3. 快速沃尔什变换(FWT)学习笔记 + 洛谷P4717 [模板]

    FWT求解的是一类问题:\( a[i] = \sum\limits_{j\bigoplus k=i}^{} b[j]*c[k] \) 其中,\( \bigoplus \) 可以是 or,and,xor ...

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

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

  5. 快速傅里叶变换(FFT)学习笔记(其一)

    再探快速傅里叶变换(FFT)学习笔记(其一) 目录 再探快速傅里叶变换(FFT)学习笔记(其一) 写在前面 为什么写这篇博客 一些约定 前置知识 多项式卷积 多项式的系数表达式和点值表达式 单位根及其 ...

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

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

  7. 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)

    再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...

  8. 快速傅里叶变换(FFT)学习笔记(其二)(NTT)

    再探快速傅里叶变换(FFT)学习笔记(其二)(NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其二)(NTT) 写在前面 一些约定 前置知识 同余类和剩余系 欧拉定理 阶 原根 求原根 NTT ...

  9. 快速沃尔什变换FWT

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

随机推荐

  1. EF性能优化-有人说EF性能低,我想说:EF确实不如ADO.NET

    十年河东,十年河西,莫欺少年穷. EF就如同那个少年,ADO.NET则是一位壮年.毕竟ADO.NET出生在EF之前,而EF所走的路属于应用ADO.NET. 也就是说:你所写的LINQ查询,最后还是要转 ...

  2. MySQL调优基础, 与hikari数据库连接池配合

    1.根据硬件配置系统参数 wait_timeout  非交互连接的最大存活时间, 10-30min max_connections   全局最大连接数 默认100 根据情况调整 back_log   ...

  3. 在asp.net web form项目中添加webapi接口

    我有一个支付宝服务网关是ASP.NET WEB FORM项目,但是最近这个网关需要对外提供几个接口,想了下,使用web api比较合适,实现很简单,GO 1,首先添加一个文件夹名字叫App_Start ...

  4. JavaScript 利用 async await 实现 sleep 效果

    const sleep = (timeountMS) => new Promise((resolve) => { setTimeout(resolve, timeountMS); }); ...

  5. koa2入门(2) koa-router 路由处理

    项目地址:https://github.com/caochangkui/demo/tree/koa-test 1. 创建项目 创建目录 koa-test npm init 创建 package.jso ...

  6. 挂载银行前置机Ukey到windows server2012虚拟机的操作记录

    公司有跟银行对接的金融业务,需要配置银行前置机环境.通过KVM的WebVirtMgr管理平台创建windows server2008虚拟机,安装参考:kvm虚拟化管理平台WebVirtMgr部署-完整 ...

  7. Keepalived基础知识-运维小结

    keepalived介绍keepalived观察其名可知,保持存活,在网络里面就是保持在线了,也就是所谓的高可用或热备,它集群管理中保证集群高可用的一个服务软件,其功能类似于heartbeat,用来防 ...

  8. Command Analyze failed with a nonzero exit code

    在运行RN项目的时候,报 Command Analyze failed with a nonzero exit code ,试着将build System 修改下

  9. LINUX内核分析第六周学习总结——进程的描述与创建

    LINUX内核分析第六周学习总结--进程的描述与创建 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc ...

  10. BF算法和KMP算法 python实现

    BF算法 def Index(s1,s2,pos = 0): """ BF算法 """ i = pos j = 0 while(i < ...