FMT/FWT学习笔记

FMT/FWT是算法竞赛中求or/and/xor卷积的算法,数据处理中也有应用。

网上的命名方法有很多。

这里我们选这个博客的,把AND/OR命名为FMT,XOR命名为FWT

如果是整数,我们认为\(\cup\)和\(\cap\)运算是二进制下的,也就是\(\text{|和&}\),这可以帮我们理解之后的集合幂级数。

FMT 快速莫比乌斯变换 OR卷积

与FMT可以求出

\[C=\sum_i C_i=\sum_i\sum_{j\cup k=i}A_j*B_k=A\cup B
\]

因为前缀的并是前缀,容易得到过程是把A、B求子集前缀和,得到FMTor数组

\[FMT(A)_n=\sum_{i \subseteq n}A_i
\]

与FFT类似,FMTor数组直接乘起来就得到了C的FMTor数组,证明如下:

\[FMT(A)_n * FMT(B)_n=\sum_{i \subseteq x} A_{i} \sum_{j \subseteq x} B_{j}=\sum_{i, j \subseteq x} A_{i} B_{j}=\sum_{k \subseteq x} \sum_{i \cup j=k} A_{i} B_{j}=FMT(C)_n
\]

最后换回去(子集和变原数组)就得到了C

至于具体怎么算前缀和,挂张图,想必大家见过很多次了吧(箭头表示加法)

如上图,讨论这一层的1在不在下一个集合即可。

代码:

const int N = 2e5+200;
const ll mod = 998244353;
int a[N];
void FMTor(int *a,int n,int opt){
for(int l=2;l<=n;l<<=1){
int m=l>>1;
for(int *g=a;g!=a+n;g+=l){
for(int k=0;k<m;k++){
if(opt==1) g[k+m]=(g[k+m]+g[k])%mod;
else g[k+m]=(g[k+m]-g[k]+mod)%mod;
}
}
}
}

跟FFT非常的像...

AND卷积

\[C=\sum_i C_i=\sum_i\sum_{j\cap k=i}A_j*B_k=A\cap B
\]

然后猜测FMTand为后缀和(后缀的交为后缀),

\[FMT(A)_n=\sum_{n\subseteq i} A(i)
\]

同样的,证明:

\[FMT(A)_n * FMT(B)_n=\sum_{n\subseteq i} A_i\sum_{n\subseteq j} B_j=\sum_{n\subseteq i,j} A_i*B_j=\sum_{n\subseteq x}\sum_{i\cap j=x}A_i*B_j=FMT(C)_n
\]

和OR是不是有几分相似?

const int N = 2e5+200;
const ll mod = 998244353;
int a[N];
void FMTand(int *a,int n,int opt){
for(int l=2;l<=n;l<<=1){
int m=l>>1;
for(int *g=a;g!=a+n;g+=l){
for(int k=0;k<m;k++){
if(opt==1) g[k]=(g[k]+g[k+m])%mod;
else g[k]=(g[k]-g[k+m]+mod)%mod;
}
}
}
}

快速沃尔什变换(FWT/XOR卷积)

这个稍微难点

我们要求

\[C=\sum_i C_i=\sum_i\sum_{j\oplus k=i}A_j*B_k=A\oplus B
\]

这里的FWT数组不是那么显然,考虑构造。

由于线性相关,令

\[FWT(A)_x=\sum_{i=0}^ng(x,i)A_i
\]

那么

\[\sum_{i=0}^{n} g(x, i) C_{i}=\sum_{j=0}^{n} g(x, j) A_{j} \sum_{k=0}^{n} g(x, k) B_{k}
\]

带入C的定义,

\[\sum_{j=0}^{n} \sum_{k=0}^{n} g(x, j \oplus k) A_{j} B_{k}=\sum_{j=0}^{n} \sum_{k=0}^{n} g(x, j) g(x, k) A_{j} B_{k}
\]

对比系数,

\[g(x,j\oplus k)=g(x,j)g(x,k)
\]

异或有一系列性质:

  1. \((j\cap x)\oplus (k\cap x)=(j\oplus k)\cap x\)

    不知道这个的可以讨论一波:在第\(i\)位,

    \[\begin{array}{|c|c|c|c|c|c|c|c|}j & k &x &j\cap x &k\cap x&(j\cap x)\oplus (k\cap x)&j \oplus k&(j\oplus k)\cap x\\0&0&0&0&0&0&0&0\\0&0&1&0&0&0&0&0\\0&1&0&0&0&0&1&0\\0&1&1&0&1&1&1&1\\1&0&0&0&0&0&1&0\\1&0&1&1&0&1&1&1\\1&1&0&1&1&0&0&0\\1&1&1&1&1&0&0&0\\\end{array}
    \]

  2. 异或前后1的个数奇偶性不变(对吧)

那么我们定义\(|x|\)为二进制下集合大小,即1的个数,g就可以赋值了

\[g(x, i)=(-1)^{|i \cap x|}
\]

\[FWT(A)_{x}=\sum_{i=0}^{n}(-1)^{|i \cap x|} A_{i}
\]

考虑怎么递推算这个东西,考虑加不加上区间长度i

由于枚举i为2的次幂从小到大,新加上i集合大小一定加一,系数乘负一,否则不变。

那么有:

\[A[j+k]=A_0[j+k]+A_0[j+k+i]\\A[j+k+i]=A_0[j+k]-A_0[j+k+i]\\
\]

反过来,解方程可以得到

\[A_0[j+k]=\frac{A[j+k]+A[j+k+i]}{2}\\A_0[j+k+i]=\frac{A[j+k]-A_[j+k+i]}{2}\\
\]

代码:

const int N = 2e5+200;
const int mod = 998244353;
const int inv2 = 499122177;
int a[N];
void FWT(int *a,int n,int opt){
for(int l=2;l<=n;l<<=1){
int m=l>>1;
for(int *g=a;g!=a+n;g+=l){
for(int k=0;k<m;k++){
ll t=g[k+m];
g[k+m]=(g[k]-g[k+m]+mod)%mod;
g[k]=(g[k]+t)%mod;//草,有蝴蝶变换内味了
//提醒一下这和FFT的区别:没有乘单位根
if(opt==-1) g[k]=1ll*g[k]*inv2%mod,g[k+m]=1ll*g[k+m]*inv2%mod;
//而且反演的时候也不一样
}
}
}
}

就愉快地学完啦!是不是比FFT简单

FMT/FWT学习笔记的更多相关文章

  1. FWT学习笔记

    FWT学习笔记 引入 一般的多项式乘法是这样子的: \(c_i=\sum_{i,j}a_j*b_k*[j+k==i]\) 但是如果我们将这个乘法式子里面的+号变换一下变成其他的运算符号呢? \(c_i ...

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

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

  3. FWT 学习笔记

    FWT学习笔记 好久以前写的,先粘上来 定义数组 \(n=2^k\) \(A=[a_0,a_1,a_2,a_3,...,a_{n-1}]\) 令\(A_0=[a_0,a_1,a_2,...,a_{\f ...

  4. $\text {FWT}$学习笔记

    \(\text {FWT}\) 学习笔记 正常项的\(\text {FWT}\) 在\(\text {OI}\)中,我们经常会碰到这种问题: 给出一个长度为\(n\)的序列\(a_{1,2,...,n ...

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

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

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

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

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

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

  8. 卷积理论 & 高维FWT学习笔记

    之前做了那么多生成函数和多项式卷积的题目,结果今天才理解了优化卷积算法的实质. 首先我们以二进制FWT or作为最简单的例子入手. 我们发现正的FWT or变换就是求$\hat{a}_j=\sum_{ ...

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

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

随机推荐

  1. SQL基础系列(3)-变量、函数、存储过程等

    1.    变量 定义变量 DECLARE @a INT 赋值 PRINT @a ) --select 赋值 SELECT @name='zcx' PRINT @name SELECT @name=F ...

  2. 答好友困惑:Java零基础如何入门,不知道怎么学,迷茫ING

    作者:程序员小跃 几个星期之前,我在知乎上看到一个提问,说是:对于完全没有经验零基础自身的数学底子也很弱学习Java应该怎么学习呢?想着类似的问题我也有过回答,并且反馈还是蛮好的,就参考之前的思路回答 ...

  3. Redis之ziplist源码分析

    一.ziplist简介 从上一篇分析我们知道quicklist的底层存储使用了ziplist(压缩列表),由于压缩列表本身也有不少内容,所以重新开了一篇,在正式源码之前,还是先看下ziplist的特点 ...

  4. 自己写的一个HTML的小网页

    上次在上直播课的时候,教员提到了html这种标记语言.自己就在W3school上面学了一点点关于html的一些皮毛,自己动手写了一个小网页,同时自己对CTF这一块比较感兴趣,但是自己还是一个干干净净的 ...

  5. JavaScript中的作用域和作用域链(边学边写)[看着别人的博客纯手敲]

    作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域的工作原理.今天这篇文章对JavaScript作用域和作用域链简单的介绍,希望能帮 ...

  6. 全网最全最细的jmeter接口测试教程以及接口测试流程详解

    一.Jmeter简介 ​ Jmeter是由Apache公司开发的一个纯Java的开源项目,即可以用于做接口测试也可以用于做性能测试. Jmeter具备高移植性,可以实现跨平台运行. Jmeter可以实 ...

  7. 接触 Jmeter

    Apache JMeter是 Apache组织开发的基于 Java的开源压力测试工具.接口以及自动化测试. JMeter 可以进行参数化测试,实现自动化脚本与测试数据分离,能够对应用程序做功能/回归测 ...

  8. CentOS 使用中问题记录

    ⚠️使用yum提示Error: rpmdb open failed的解决方案 清除原rpmdb文件,这一步可能不用操作,直接进行第2步 # rm -f /var/lib/rpm/__db.* 重建rp ...

  9. coding++:@DisallowConcurrentExecution 注解的作用

    Quartz定时任务默认都是并发执行的,不会等待上一次任务执行完毕,只要间隔时间到就会执行, 如果定时任执行太长,会长时间占用资源,导致其它任务堵塞. 在Spring中这时需要设置concurrent ...

  10. Java 多线程 -- 理解锁:手动实现可重入锁和不可重入锁

    JDK提供的大多数内置锁都是可重入的,也就是 说,如果某个线程试图获取一个已经由它自己持有的锁时,那么这个请求会立 刻成功,并且会将这个锁的计数值加1,而当线程退出同步代码块时,计数器 将会递减,当计 ...