FWT能解决什么

  • 有的时候我们会遇到要求一类卷积,如下:

    Ci=∑j⊕k=iAj∗Bk\large C_i=\sum_{j⊕k=i}A_j*B_kCi​=j⊕k=i∑​Aj​∗Bk​此处乘号为普通乘法,⊕⊕⊕表示一种位运算,如 and(&)、and(\&)、and(&)、 or(∣)、or(|)、or(∣)、异或 xor(xor(xor(^)))

    LaTeX\Large\LaTeXLATE​X打不了 ^ 啊…qwq

FWT思想

  • 首先因为是位运算,所以需要按位分解。又因为是卷积的形式,联想到FFTFFTFFT中利用了一种分治优化降低时间复杂度,所以我们首先把多项式拓展到222的次幂长度,方便按位分治
  • FWTFWTFWT的思想就是利用一种向量变换来简化运算,首先我们定义向量VVV(此处可理解为数组或多项式)的正变换为FWT[V]FWT[V]FWT[V],逆变换为FWT−1[V]FWT^{-1}[V]FWT−1[V]
    • 先拿and(&)and(\&)and(&)的情况举例,根据位运算常识有

      (i&k) & (j&k)=(i&j) & k(i\&k)~\&~(j\&k)=(i\&j)~\&~k(i&k) & (j&k)=(i&j) & k
    • 所以构造FWT[V]i=∑(j&i)=iVjFWT[V]_i=\sum_{(j\&i)=i}V_jFWT[V]i​=∑(j&i)=i​Vj​

      则有 FWT[C]i=FWT[A]i∗FWT[B]iFWT[C]_i=FWT[A]_i*FWT[B]_iFWT[C]i​=FWT[A]i​∗FWT[B]i​
    • 那么我们只需要求出FWT[A],FWT[B]FWT[A],FWT[B]FWT[A],FWT[B],就能得到FWT[C]FWT[C]FWT[C],然后通过逆变换求出CCC

变换与逆变换具体实现

  • 像FFT一样,分治求FWT[V]FWT[V]FWT[V]。拿andandand运算举例
  • 将一个长度为lenlenlen区间二分,那么左边和右边分别是最高位为0/10/10/1的数,此时递归处理左右两边。相当于先不考虑最高位,递归处理左右两边长度为len/2len/2len/2的答案
  • 要想将两个区间合并,由于是andandand运算,两个数的与运算只会变小,那么只会是右边的区间对左边造成贡献
  • 记左边处理出来的答案为XiX_iXi​,右边处理出来的答案为YiY_iYi​,合并后的答案为AnsiAns_iAnsi​,XXX与YYY的实际含义为{Xi=∑i&j=i,j在左边VjYi=∑i&j=i,j在右边Vj\Large \left\{
    \begin{aligned}
    X_i=&\sum_{i\&j=i,j在左边}V_j\\
    Y_i=&\sum_{i\&j=i,j在右边}V_j\\
    \end{aligned}
    \right.⎩⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎧​Xi​=Yi​=​i&j=i,j在左边∑​Vj​i&j=i,j在右边∑​Vj​​
  • 显然有{Ansi=Xi+YiAnsi+len/2=Yi\Large \left\{
    \begin{aligned}
    &Ans_i=X_i+Y_i\\
    &Ans_{i+len/2}=Y_i\\
    \end{aligned}
    \right.⎩⎪⎨⎪⎧​​Ansi​=Xi​+Yi​Ansi+len/2​=Yi​​
  • 求逆变换FWT[V]−1FWT[V]^{-1}FWT[V]−1时有{Xi=Ansi−Ansi+len/2Yi=Ansi+len/2\Large \left\{
    \begin{aligned}
    &X_i=Ans_i-Ans_{i+len/2}\\
    &Y_i=Ans_{i+len/2}\\
    \end{aligned}
    \right.⎩⎪⎨⎪⎧​​Xi​=Ansi​−Ansi+len/2​Yi​=Ansi+len/2​​
  • 于是我们就解决了与运算的问题,或运算可类比

异或卷积

  • 异或(xor)(xor)(xor)与其他两个有点不一样(毕竟LaTeX\Large\LaTeXLATE​X写不出来),需要多想一想
  • 异或卷积基于以下原理
    • 定义iii和jjj之间的奇偶性为(i&j)(i\&j)(i&j)中为1的位数的奇偶性,若为偶数则奇偶性是0,若为奇数则奇偶性是1。记作d(i,j)d(i,j)d(i,j)

    • 令FWT[V]i=∑d(i,j)=0Vj−∑d(i,j)=1Vj\large FWT[V]_i=\sum_{d(i,j)=0}V_j-\sum_{d(i,j)=1}V_jFWT[V]i​=∑d(i,j)=0​Vj​−∑d(i,j)=1​Vj​

      就有了FWT[C]i=FWT[A]i∗FWT[B]i\large FWT[C]_i=FWT[A]_i*FWT[B]_iFWT[C]i​=FWT[A]i​∗FWT[B]i​

      • 证明为d(i,k) xor d(j,k)=d(i xor j,k)d(i,k)~xor~d(j,k)=d(i~xor~j,k)d(i,k) xor d(j,k)=d(i xor j,k)

        • 将(i&k),(j&k)(i\&k),(j\&k)(i&k),(j&k)同时减去它们的相与的值(i&k)&(j&k)(i\&k)\&(j\&k)(i&k)&(j&k),它们的相对奇偶性(可以理解吧)不变,减去后(i&k),(j&k)(i\&k),(j\&k)(i&k),(j&k)在二进制下没有同时为111的位,所以异或可以直接相加
        • 所以当d(i,k)=d(j,k)d(i,k)=d(j,k)d(i,k)=d(j,k),同时减去后奇偶性还是相等,那么(i xor j)&k(i~xor~j)\&k(i xor j)&k的奇偶性=两个相等的奇偶性加起来=0=d(i,k) xor d(j,k)d(i,k)~xor~d(j,k)d(i,k) xor d(j,k)
        • 所以当d(i,k)!=d(j,k)d(i,k)!=d(j,k)d(i,k)!=d(j,k),同时减去后奇偶性还是不等,那么(i xor j)&k(i~xor~j)\&k(i xor j)&k的奇偶性=两个不等的奇偶性加起来=1=d(i,k) xor d(j,k)d(i,k)~xor~d(j,k)d(i,k) xor d(j,k)
      • 证毕(看懵逼的写两个二进制数来看看,很好理解的)
    • 看看怎么分治,此处XXX与YYY的实际含义为{Xi=∑d(i,j)=0,j在左边Vj−∑d(i,j)=1,j在左边VjYi=∑d(i,j)=0,j在右边Vj−∑d(i,j)=1,j在右边Vj\Large \left\{
      \begin{aligned}
      X_i=&\sum_{d(i,j)=0,j在左边}V_j-\sum_{d(i,j)=1,j在左边}V_j\\
      Y_i=&\sum_{d(i,j)=0,j在右边}V_j-\sum_{d(i,j)=1,j在右边}V_j\\
      \end{aligned}
      \right.⎩⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎧​Xi​=Yi​=​d(i,j)=0,j在左边∑​Vj​−d(i,j)=1,j在左边∑​Vj​d(i,j)=0,j在右边∑​Vj​−d(i,j)=1,j在右边∑​Vj​​

    • 有{Ansi=Xi+Yi.................(1)Ansi+len/2=Xi−Yi.........(2)\Large \left\{
      \begin{aligned}
      &Ans_i=X_i+Y_i.................(1)\\
      &Ans_{i+len/2}=X_i-Y_i.........(2)\\
      \end{aligned}
      \right.⎩⎪⎨⎪⎧​​Ansi​=Xi​+Yi​.................(1)Ansi+len/2​=Xi​−Yi​.........(2)​

    • 怎么想呢,分类讨论吧。由于:

      • (1)(1)(1)对于左边区间的iii,根据X,YX,YX,Y的定义,显然满足
      • (2)(2)(2)而对于右边区间的iii
        • 当jjj在左边区间,j and ij~and~ij and i的值一定和j and (i−len/2)j~and~(i-len/2)j and (i−len/2)的值相等。所以加上XiX_iXi​
        • 当jjj在右边区间,j and ij~and~ij and i的值一定和j and (i−len/2)j~and~(i-len/2)j and (i−len/2)的值相反。所以减去YiY_iYi​
    • 逆变换可自行推导(或看下方代码)

Luogu板题链接:P4717 【模板】快速沃尔什变换

写法跟FFT,NTT一模一样,还要更简(hao)单(bei)

AC code

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. using namespace std;
  5. typedef long long LL;
  6. const int MAXN = 1<<17;
  7. const int mod = 998244353;
  8. const int inv2 = 499122177;
  9. int n, a[MAXN], b[MAXN];
  10. int a1[MAXN], a2[MAXN];
  11. inline void FWT_or(int arr[], const int& len, const int& flg)
  12. {
  13. register int x, y;
  14. for(register int i = 2; i <= len; i<<=1)
  15. for(register int j = 0; j < len; j += i)
  16. for(register int k = j; k < j + i/2; ++k)
  17. {
  18. x = arr[k], y = arr[k + i/2];
  19. if(~flg) arr[k + i/2] = (x + y) % mod;
  20. else arr[k + i/2] = (y - x + mod) % mod;
  21. }
  22. }
  23. inline void FWT_and(int arr[], const int& len, const int& flg)
  24. {
  25. register int x, y;
  26. for(register int i = 2; i <= len; i<<=1)
  27. for(register int j = 0; j < len; j += i)
  28. for(register int k = j; k < j + i/2; ++k)
  29. {
  30. x = arr[k], y = arr[k + i/2];
  31. if(~flg) arr[k] = (x + y) % mod;
  32. else arr[k] = (x - y + mod) % mod;
  33. }
  34. }
  35. inline void FWT_xor(int arr[], const int& len, const int& flg)
  36. {
  37. register int x, y;
  38. for(register int i = 2; i <= len; i<<=1)
  39. for(register int j = 0; j < len; j += i)
  40. for(register int k = j; k < j + i/2; ++k)
  41. {
  42. x = arr[k], y = arr[k + i/2];
  43. if(~flg) arr[k] = (x + y) % mod, arr[k + i/2] = (x - y + mod) % mod;
  44. else arr[k] = (LL)(x + y) * inv2 % mod, arr[k + i/2] = (LL)(x - y + mod) * inv2 % mod;
  45. }
  46. }
  47. inline void solve_or(const int& len)
  48. {
  49. memcpy(a1, a, sizeof a);
  50. memcpy(a2, b, sizeof b);
  51. FWT_or(a1, len, 1);
  52. FWT_or(a2, len, 1);
  53. for(int i = 0; i < len; ++i)
  54. a2[i] = (LL)a1[i] * a2[i] % mod;
  55. FWT_or(a2, len, -1);
  56. for(int i = 0; i < len; ++i)
  57. printf("%d%c", a2[i], i == len-1 ? '\n' : ' ');
  58. }
  59. inline void solve_and(const int& len)
  60. {
  61. memcpy(a1, a, sizeof a);
  62. memcpy(a2, b, sizeof b);
  63. FWT_and(a1, len, 1);
  64. FWT_and(a2, len, 1);
  65. for(int i = 0; i < len; ++i)
  66. a2[i] = (LL)a1[i] * a2[i] % mod;
  67. FWT_and(a2, len, -1);
  68. for(int i = 0; i < len; ++i)
  69. printf("%d%c", a2[i], i == len-1 ? '\n' : ' ');
  70. }
  71. inline void solve_xor(const int& len)
  72. {
  73. memcpy(a1, a, sizeof a);
  74. memcpy(a2, b, sizeof b);
  75. FWT_xor(a1, len, 1);
  76. FWT_xor(a2, len, 1);
  77. for(int i = 0; i < len; ++i)
  78. a2[i] = (LL)a1[i] * a2[i] % mod;
  79. FWT_xor(a2, len, -1);
  80. for(int i = 0; i < len; ++i)
  81. printf("%d%c", a2[i], i == len-1 ? '\n' : ' ');
  82. }
  83. int main ()
  84. {
  85. scanf("%d", &n); n = 1<<n;
  86. for(int i = 0; i < n; ++i) scanf("%d", &a[i]);
  87. for(int i = 0; i < n; ++i) scanf("%d", &b[i]);
  88. solve_or(n);
  89. solve_and(n);
  90. solve_xor(n);
  91. }

初学FWT(快速沃尔什变换) 一点心得的更多相关文章

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

    FWT快速沃尔什变换学习笔记 1.FWT用来干啥啊 回忆一下多项式的卷积\(C_k=\sum_{i+j=k}A_i*B_j\) 我们可以用\(FFT\)来做. 甚至在一些特殊情况下,我们\(C_k=\ ...

  2. [学习笔记]FWT——快速沃尔什变换

    解决涉及子集配凑的卷积问题 一.介绍 1.基本用法 FWT快速沃尔什变换学习笔记 就是解决一类问题: $f[k]=\sum_{i\oplus j=k}a[i]*b[j]$ 基本思想和FFT类似. 首先 ...

  3. 浅谈算法——FWT(快速沃尔什变换)

    其实FWT我啥都不会,反正就是记一波结论,记住就好-- 具体证明的话,推荐博客:FWT快速沃尔什变换学习笔记 现有一些卷积,形如 \(C_k=\sum\limits_{i\lor j=k}A_i*B_ ...

  4. 知识点简单总结——FWT(快速沃尔什变换),FST(快速子集变换)

    知识点简单总结--FWT(快速沃尔什变换),FST(快速子集变换) 闲话 博客园的markdown也太傻逼了吧. 快速沃尔什变换 位运算卷积 形如 $ f[ i ] = \sum\limits_{ j ...

  5. FWT快速沃尔什变换例题

    模板题 传送门 #include<bits/stdc++.h> #define ll long long #define max(a,b) ((a)>(b)?(a):(b)) #de ...

  6. FWT快速沃尔什变换——基于朴素数学原理的卷积算法

    这是我的第一篇学习笔记,如有差错,请海涵... 目录 引子 卷积形式 算法流程 OR卷积 AND卷积 XOR卷积 模板 引子 首先,考虑这是兔子 数一数,会发现你有一只兔子,现在,我再给你一只兔子 再 ...

  7. FWT快速沃尔什变换

    前言 学多项式怎么能错过\(FWT\)呢,然而这真是个毒瘤的东西,蒟蒻就只会背公式了\(\%>\_<\%\) 或卷积 \[\begin{aligned}\\ tf(A) = (tf(A_0 ...

  8. 关于快速沃尔什变换(FWT)的一点学习和思考

    最近在学FWT,抽点时间出来把这个算法总结一下. 快速沃尔什变换(Fast Walsh-Hadamard Transform),简称FWT.是快速完成集合卷积运算的一种算法. 主要功能是求:,其中为集 ...

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

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

随机推荐

  1. Windows10无法访问局域网文件夹

    给目录guest用户,并启用guest 最近硬盘存储不开资料在同学的电脑存储了然后使用Windows提供的共享文件夹功能提供文件访问,可是今天上午一不小心把系统玩挂了重新安装了Windows10专业工 ...

  2. Hyperledger Fabric 入门 first-network 搭建

    1.准备环境: 安装git.docker.curl.go [root@test_vonedao_83 fabric]# git --version git version 1.8.3.1 [root@ ...

  3. Python之路【第二十九篇】:django ORM模型层

    ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的 ...

  4. 全栈项目|小书架|服务器端-NodeJS+Koa2 实现搜索功能

    搜索功能会包含:热搜.搜索列表. 热搜功能在电商的搜索中经常看到,热搜数据的来源有两种 用户真实的搜索数据,根据算法进行排序 人为推送的数据 想想微博热搜是可以买的就知道热搜功能多么重要了. 我采用第 ...

  5. Linux 服务器 关闭FTP匿名访问

    service vsftpd status //查看FTP运行状态 vim /etc/vsftpd/vsftpd.conf //修改配置文件 找到vsftpd.conf中的 anonymous_ena ...

  6. java之hibernate之加载策略和抓取策略

    1.加载策略:指hibernate查询数据时,采用什么样的方式将数据写入内存.Hibernate中提供了两种方式来加载数据:懒加载和即时加载. 2.懒加载又称延迟加载,指使用hiberante API ...

  7. Java自学-类和对象 方法重载

    什么是Java 方法重载 方法的重载指的是方法名一样,但是参数类型不一样 步骤 1 : attack方法的重载 有一种英雄,叫做物理攻击英雄 ADHero 为ADHero 提供三种方法 public ...

  8. div中的“内容”水平垂直居中

    1. div高度自适应的情况 div在不设置高度的时候,会被里面的内容撑开,内容自动填充在div中,无论是一行内容还是多行内容,此时不需要设置垂直居中,内容自动在中间的, 想要看的更直观些,只需要加上 ...

  9. 解决for循环中异步处理(异步变同步)

    前沿:参考ES6语法的async/await的处理机制 先上一段代码 function getMoney(){ var money=[100,200,300] for( let i=0; i<m ...

  10. Django:基于调试组插件go-debug-toolbar

    1.django-debug-toolbar 介绍 django-debug-toolbar 是一组可配置的面板,可显示有关当前请求/响应的各种调试信息,并在单击时显示有关面板内容的更多详细信息.返回 ...