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

OR的FWT

快速解决:

\[C[i]=\sum_{j|k=i} A[j]B[k]
\]

FWT使得我们

\[FWT(C)=FWT(A)*FWT(B)
\]

其中\(*\)是点积,就是对应位置乘起来。

而对于\(orFWT\),

\[C'[i]=FWT(C)[i]=\sum_{j\subseteq i}C[j]
\]

那么证明一下:

\[\begin{array}
&C'[i]&=\sum_{j\subseteq i} C[j]
\\
&=\sum_{j\subseteq i}\sum_{p|k=j} A[p]B[k]
\\
&=\sum_{p\subseteq i,k\subseteq i} A[p]B[k]
\\
&=\sum_{p\subseteq i} A[p]\sum_{k\subseteq i}B[k]
\\
&=A'[i]B'[i]
\end{array}
\]

考虑\(A\)和\(A'\)的关系,其中\(A_0,A_1\)分别代表\(A\)的前\(2^{k-1}\)和后这么多项(下标都从0开始)。他们的差别是\(2^{k-1}\)位上的不同。其他相似。

\[FWT(A)=
\begin{cases}
FWT(A_0),FWT(A_1+A_0) & k>0
\\
A & k=0
\end{cases}
\]

逗号表示依次连接。

复杂度\(T(n)=2T(n/2)+T(n)=O(n\log n)\),而一般来说\(n=2^m\)那么就是\(O(m2^m)\)

考虑\(IFWT\)

照猫画虎即可

\[IFWT(A')=
\begin{cases}
IFWT(A'_0),IFWT(A'_1-A'_0) & k>0
\\
A' & k=0
\end{cases}
\]

代码

inline void FWT_OR(int*a,const int&tag,const int&len){
for(int t=1;t<len;t<<=1)
for(int i=0;i<len;i+=t<<1)
for(int k=0;k<t;++k)
a[t+i+k]=(a[t+i+k]+a[t+i]*tag+mod)%mod;
}

AND的FWT

同样地,快速解决

\[C[i]=\sum_{j\& k=i}A[j]B[k]
\]

可以构造\(C'[i]=FWT(C)[i]=\sum_\limits{i\subseteq j} C[j]\),至于为什么构造,这个\(j\&k=i\)可以看做\(i\)是\(j,k\)的子集。

同样有

\[FWT(C)=FWT(A)*FWT(B)
\]

证明:

\[\begin{array}
&C'[i]&=\sum_{i\subseteq j} C[j]
\\
&= \sum_{i\subseteq j} \sum_{k\&p=j}A[k]B[p]
\\
&= \sum_{i\subseteq k,i\subseteq p}A[k]B[p]
\\
&= \sum_{i\subseteq k}A[k]\sum_{i\subseteq p}B[p]
\\
&=A'[i]B'[i]
\end{array}
\]

同样地

\[FWT(A)=
\begin{cases}
FWT(A_0+A_1),FWT(A_1)&k>0
\\
A&k=0
\end{cases}
\]

同样的\(T(n)=O(m2^m)\)

同样地

\[IFWT(A')=
\begin{cases}
IFWT(A'_0-A'_1),IFWT(A_1) &k>0
\\
A'&k=0
\end{cases}
\]

同样地

inline void FWT_AND(int*a,const int&tag,const int&len){
for(int t=1;t<len;t<<=1)
for(int i=0;i<len;i+=t<<1)
for(int k=0;k<t;++k)
a[t+i]=(a[t+i]+a[t+i+k]*tag+mod)%mod;
}

XOR的FWT

也是快速解决

\[C[i]=\sum_{j\oplus k=i}A[j]B[k]
\]

这里\(FWT(X)\)貌似没有很直观的意义了,推式子的话其实也能理解

\[FWT(C)=FWT(A)*FWT(B)
\]

这里记录一个符号\(A\oplus B=C\)

那么

\(C=A\oplus B\)

拆成前后两半

\[C_0=A_0\oplus B_0+A_1\oplus B_1
\\
C_1=A_0\oplus B_1+A_1\oplus B_0
\]

\[X_0=(A_0+A_1)\oplus (B_0+B_1)
\\
X_1=(A_0-A_1)\oplus (B_0-B_1)
\]

然后?

\[C_0={X_0+X_1\over 2}
\\
C_1={X_0-X_1 \over 2}
\]

但是好像学这个无法和各路大佬进行交流,并且我好像并没有学会,那么...

\[FWT(A)=\begin{cases}(FWT(A_0)+FWT(A_1),FWT(A_0)-FWT(A_1)) & n>0\\A & n=0\end{cases}
\]

用循环实现的技巧和NTT一致,控制长度,控制第几段,控制段内的循环变量

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm> using namespace std; typedef long long ll;
inline int qr(){
int ret=0,f=0,c=getchar();
while(!isdigit(c))f|=c==45,c=getchar();
while(isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=1<<18|1;
const int mod=998244353; inline void FWT_OR(int*a,const int&len,const int&tag){
for(int t=1;t<len;t<<=1)
for(int i=0;i<len;i+=t<<1)
for(int k=0;k<t;++k)
a[t+i+k]=(0ll+a[t+i+k]+a[i+k]*tag+mod)%mod;
} inline void FWT_AND(int*a,const int&len,const int&tag){
for(int t=1;t<len;t<<=1)
for(int i=0;i<len;i+=t<<1)
for(int k=0;k<t;++k)
a[i+k]=(0ll+a[i+k]+a[t+i+k]*tag+mod)%mod;
} inline void FWT_XOR(int*a,const int&len,const int&tag){
int opt=tag==1?1:((mod+1)>>1);
for(int t=1;t<len;t<<=1)
for(int i=0;i<len;i+=t<<1)
for(int k=0;k<t;++k){
int t0=a[i+k],t1=a[i+k+t];
if(tag==1) a[i+k]=(t0+t1)%mod,a[i+k+t]=(t0-t1+mod)%mod;
else a[i+k]=1ll*(t0+t1)%mod*opt%mod,a[i+k+t]=1ll*(t0-t1+mod)%mod*opt%mod;
}
} int n,k;
int a[maxn],b[maxn],c[maxn];
int A[maxn],B[maxn]; int main(){
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
n=qr();
for(int t=0;t<1<<n;++t) a[t]=qr();
for(int t=0;t<1<<n;++t) b[t]=qr();
size_t s=(1<<n)*4; memcpy(A,a,s); memcpy(B,b,s);
FWT_OR(A,1<<n,1); FWT_OR(B,1<<n,1);
for(int t=0;t<1<<n;++t) c[t]=1ll*A[t]*B[t]%mod;
FWT_OR(c,1<<n,-1);
for(int t=0;t<1<<n;++t) printf("%d ",c[t]);
putchar('\n'); memcpy(A,a,s); memcpy(B,b,s);
FWT_AND(A,1<<n,1); FWT_AND(B,1<<n,1);
for(int t=0;t<1<<n;++t) c[t]=1ll*A[t]*B[t]%mod;
FWT_AND(c,1<<n,-1);
for(int t=0;t<1<<n;++t) printf("%d ",c[t]);
putchar('\n'); memcpy(A,a,s); memcpy(B,b,s);
FWT_XOR(A,1<<n,1); FWT_XOR(B,1<<n,1);
for(int t=0;t<1<<n;++t) c[t]=1ll*A[t]*B[t]%mod;
FWT_XOR(c,1<<n,-1);
for(int t=0;t<1<<n;++t) printf("%d ",c[t]);
putchar('\n'); return 0;
}

【学习笔鸡】快速沃尔什变换FWT的更多相关文章

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

    一个数学不好的菜鸡的快速沃尔什变换(FWT)学习笔记 曾经某个下午我以为我会了FWT,结果现在一丁点也想不起来了--看来"学"完新东西不经常做题不写博客,就白学了 = = 我没啥智 ...

  2. 快速沃尔什变换FWT

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

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

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

  4. 【学习笔鸡】整体二分(P2617 Dynamic Rankings)

    [学习笔鸡]整体二分(P2617 Dynamic Rankings) 可以解决一些需要树套树才能解决的问题,但要求询问可以离线. 首先要找到一个具有可二分性的东西,比如区间\(k\)大,就很具有二分性 ...

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

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

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

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

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

    感觉快速沃尔什变换和快速傅里叶变换有很大的区别啊orz 不是很明白为什么位运算也可以叫做卷积(或许不应该叫卷积吧) 我是看 http://blog.csdn.net/liangzhaoyang1/ar ...

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

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

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

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

随机推荐

  1. QQ第三方登录报错error=-1

    qq 第三方登录报错error=-1 再次实例化qc类.

  2. [wikipedia] List of free and open-source software packages

    List of free and open-source software packages From Wikipedia, the free encyclopedia     This articl ...

  3. js日期拓展方法

    最近项目中使用了大量关于日期的操作遂将其整理如下: /** * 格式化日期 * @param {String} fmt [日期类型 默认为年月日(yyyy-MM-dd)] */ Date.protot ...

  4. python基础之逻辑题(2)

    python基础之逻辑题(2) 1.若k为整数,下列while循环执行的次数为? 2.请输出正确结果-----numbers? 3.求结果-----math?   4.求结果-----sum? 5.输 ...

  5. behavior planning——12.example cost funtion -lane change penalty

      In the image above, the blue self driving car (bottom left) is trying to get to the goal (gold sta ...

  6. Getting started with the basics of programming exercises_2

    1.编写简单power函数 #include<stdio.h> int power(int m, int n); // test power function int main(void) ...

  7. laravel博客后台操作步骤

  8. centos 磁盘挂载

    1.更改磁盘格式 fdisk -l fdisk /dev/vdb mkfs.xfs /dev/vdb1 mkfs.xfs /dev/vdb1 -f 2.查看UUID blkid 3.挂载文件夹 vim ...

  9. Python--day25--抽象类

    什么是抽象类: 抽象类: #一切皆文件 import abc #利用abc模块实现抽象类 class All_file(metaclass=abc.ABCMeta): all_type='file' ...

  10. dotnet 设计规范 · 数组定义

    本文告诉大家数组定义需要知道的规范,本文翻译 docs dotnet ✓ 建议在公开的 API 使用集合而不是数组.集合可以提供更多的信息. X 不建议设置数组类型的字段为只读.虽然用户不能修改字段, ...