【学习笔鸡】快速沃尔什变换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. Flask学习之六 个人资料和头像

    英文博客地址:http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-vi-profile-page-and-avatars ...

  2. Python学习之路6☞函数,递归,内置函数

    一python中的函数 函数是逻辑结构化和过程化的一种编程方法. python中函数定义方法: def test(x): "The function definitions" x+ ...

  3. Knative 核心概念介绍:Build、Serving 和 Eventing 三大核心组件

    Knative 主要由 Build.Serving 和 Eventing 三大核心组件构成.Knative 正是依靠这三个核心组件,驱动着 Knative 这艘 Serverless 巨轮前行.下面让 ...

  4. 解决bootStrap selectpicker 下拉栏上方弹出

    最近项目中遇到了一个使用bootStrap selectpicker 进行下拉栏展示的时候出现在元素上方弹出展示的问题,可把我难受坏了,和测试互怼最终以失败告终(人家还是一个娇滴滴的小姑娘),在查了a ...

  5. vue项目配置同一局域网可使用ip访问

    1.检查 package.json文件,scripts.dev设置 host改成 "0.0.0.0" 2.config文件中找到 index.js 文件的host改成 " ...

  6. C++第5次作业

    运算符重载 定义 - 运算符重载是对已有的运算符赋予多重含义,使同一个运算符作用于不同类型的数据时导致不同行为. 运算符重载规则 - C++运算符除了少数几个,全都可以重载,且只能重载C++已有的运算 ...

  7. 2018-9-1-win10-uwp-轻量级-MVVM-框架入门-2.1.5.3199

    title author date CreateTime categories win10 uwp 轻量级 MVVM 框架入门 2.1.5.3199 lindexi 2018-09-01 16:24: ...

  8. poj2632 累死了

    题意: 给定A*B的格子,放入N个机器人,每个机器人初始位置及朝向给定.给定M条指令.指令类型有三种: 1.L:左转90°      2.R:右转90°       3.F:前进一格 问执行指令过程中 ...

  9. 买房的贷款时间是否是越长越好?https://www.zhihu.com/question/20842791

    买房的贷款时间是否是越长越好?https://www.zhihu.com/question/20842791

  10. TSLint-Angular 配置

    代码风格和语义的检查工具,帮助规范 TS 和 Angular 代码书写: 安装: => cnpm install // 安装相关依赖 全局安装 cnpm install -g tslint ty ...