FWT背板笔记
背板子.jpg
\(Fwt\)用于解决这样的问题
\]
其中\(\bigoplus\)是一种二元运算符,如\(or,and,xor\)
首先我们直接做复杂度显然高达\(4^n\),或许可以利用一些枚举子集的技术做到\(3^n\),但是还是非常难以接受
于是我们考虑能否像\(fft\)那样构造出一种变换\(tf\),使得\(tf(C)=tf(A)*tf(B)\)(这里是逐位相乘),同时快速完成这个变换以及逆变换呢
下面以\(or\)卷积为例
我们设\(tf(A)(i)=\sum_{j|i=i}A_j\)
发现这个\(j|i=i\)就是说\(j\)是\(i\)的子集啊
于是
\]
既然\(j,k\)都是\(i\)的子集,那么\(j|k\)显然也是\(i\)的子集,设\(t=j|k\)
于是
\]
我们发现如果这样构造\(tf\),我们是可以得到\(tf(A)*tf(B)=tf(C)\)这样的性质的,于是就可以像\(fft\)那样直接逐位相乘之后逆变换了
考虑如何进行变换
变换如下
\]
\(A_0\)是\(A\)的前\(2^{n-1}\)项组成的多项式,\(A_1\)是后\(2^{n-1}\)项组成的多项式
在\(n=0\)的时候,\(tf(A)=A\)成立这非常显然啊
考虑一下\(n>0\)的情况
那个\((tf(A_0),tf(A_0+A_1))\)就是把两个\(2^{n-1}\)的多项式连接起来的意思
我们对于\(tf(A)\)的前\(2^{n-1}\)项,就是\(A_0\)的变换,跟\(A_1\)没有什么关系,因为这前\(2^{n-1}\)项第\(n\)位都是\(0\),不可能跟后\(2^{n-1}\)项第\(n\)位都是\(1\)产生关系
考虑后\(2^{n-1}\)项,根据一个非常感性的理解,后\(2^{n-1}\)项的第\(n\)位都是\(1\),我们构造出多项式\(A_0+A_1\),只看后面的\(n-1\)位自然是满足我们的\(tf\)的规则的,就是\(j\)是\(i\)的子集,又由于\(i\)的第一位是\(1\),所以\(j\)的第一位是\(0\)是\(1\)都可以,所以我们直接用\(A_0+A_1\)就好了
类似的,我们也可以推出逆变换
\]
于是我们就可以写出\(or\)卷积的代码
inline void Fwtor(LL *f,int o) {
for(re int i=2;i<=len;i<<=1)
for(re int ln=i>>1,l=0;l<len;l+=i)
for(re int x=l;x<l+ln;++x)
f[ln+x]+=o*f[x];
}
\(and\)卷积和\(or\)卷积类似
我们设变换\(tf(A)(i)=\sum_{j\&i=i}A_j\)
发现\(j\&i=i\)就是说\(j\)是\(i\)的超集
我们也能相应写出变换
\]
以及逆变换
\]
以及代码
inline void Fwtand(LL *f,int o) {
for(re int i=2;i<=len;i<<=1)
for(re int ln=i>>1,l=0;l<len;l+=i)
for(re int x=l;x<l+ln;++x)
f[x]+=o*f[ln+x];
}
\(xor\)卷积就有些不一样了呀
首先我不是很知道这个变换的实际含义是什么
据fuge说是曼哈顿距离转切比雪夫距离
我们直接摆结论
\]
尝试证明一下?对不起我咕了,挂一个yyb跑路了
板子还是放上来吧
inline void Fwtxor(LL *f,int o) {
LL Inv;
if(o==1) Inv=1;else Inv=ksm(2,mod-2);
for(re int i=2;i<=len;i<<=1)
for(re int ln=i>>1,l=0;l<len;l+=i)
for(re int x=l;x<l+ln;++x) {
LL g=f[x],h=f[ln+x];
f[x]=(g+h)%mod,f[ln+x]=(g-h+mod)%mod;
f[x]=(f[x]*Inv)%mod;f[ln+x]=(f[ln+x]*Inv)%mod;
}
}
最后挂一个完整的板子吧
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=(1<<17)+6;
inline int read() {
char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int mod=998244353;
int n,len;
LL A[maxn],B[maxn],a[maxn],b[maxn];
inline void Fwtor(LL *f,int o) {
for(re int i=2;i<=len;i<<=1)
for(re int ln=i>>1,l=0;l<len;l+=i)
for(re int x=l;x<l+ln;++x)
f[x+ln]+=f[x]*o,f[x+ln]=(f[x+ln]+mod)%mod;
}
inline void Fwtand(LL *f,int o) {
for(re int i=2;i<=len;i<<=1)
for(re int ln=i>>1,l=0;l<len;l+=i)
for(re int x=l;x<l+ln;++x)
f[x]+=f[x+ln]*o,f[x]=(f[x]+mod)%mod;
}
inline void Fwtxor(LL *f,int o) {
int Inv;
if(o==1) Inv=1;else Inv=499122177;
for(re int i=2;i<=len;i<<=1)
for(re int ln=i>>1,l=0;l<len;l+=i)
for(re int x=l;x<l+ln;++x) {
int g=f[x],h=f[x+ln];
f[x]=(g+h)%mod;f[ln+x]=(g-h+mod)%mod;
f[x]=1ll*f[x]*Inv%mod;f[x+ln]=1ll*f[x+ln]*Inv%mod;
}
}
int main() {
n=read();len=(1<<n);
for(re int i=0;i<len;i++) a[i]=A[i]=read();
for(re int i=0;i<len;i++) b[i]=B[i]=read();
Fwtor(A,1),Fwtor(B,1);
for(re int i=0;i<len;i++) A[i]=1ll*A[i]*B[i]%mod;
Fwtor(A,-1);
for(re int i=0;i<len;i++) printf("%lld ",A[i]);puts("");
for(re int i=0;i<len;i++) A[i]=a[i];
for(re int i=0;i<len;i++) B[i]=b[i];
Fwtand(A,1),Fwtand(B,1);
for(re int i=0;i<len;i++) A[i]=1ll*A[i]*B[i]%mod;
Fwtand(A,-1);
for(re int i=0;i<len;i++) printf("%lld ",A[i]);puts("");
for(re int i=0;i<len;i++) A[i]=a[i];
for(re int i=0;i<len;i++) B[i]=b[i];
Fwtxor(A,1),Fwtxor(B,1);
for(re int i=0;i<len;i++) A[i]=1ll*A[i]*B[i]%mod;
Fwtxor(A,-1);
for(re int i=0;i<len;i++) printf("%lld ",A[i]);puts("");
return 0;
}
FWT背板笔记的更多相关文章
- 一个数学不好的菜鸡的快速沃尔什变换(FWT)学习笔记
一个数学不好的菜鸡的快速沃尔什变换(FWT)学习笔记 曾经某个下午我以为我会了FWT,结果现在一丁点也想不起来了--看来"学"完新东西不经常做题不写博客,就白学了 = = 我没啥智 ...
- FWT学习笔记
FWT学习笔记 引入 一般的多项式乘法是这样子的: \(c_i=\sum_{i,j}a_j*b_k*[j+k==i]\) 但是如果我们将这个乘法式子里面的+号变换一下变成其他的运算符号呢? \(c_i ...
- 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 ...
- FMT/FWT学习笔记
目录 FMT/FWT学习笔记 FMT 快速莫比乌斯变换 OR卷积 AND卷积 快速沃尔什变换(FWT/XOR卷积) FMT/FWT学习笔记 FMT/FWT是算法竞赛中求or/and/xor卷积的算法, ...
- $\text {FWT}$学习笔记
\(\text {FWT}\) 学习笔记 正常项的\(\text {FWT}\) 在\(\text {OI}\)中,我们经常会碰到这种问题: 给出一个长度为\(n\)的序列\(a_{1,2,...,n ...
- 快速沃尔什变换 (FWT)学习笔记
证明均来自xht37 的洛谷博客 作用 在 \(OI\) 中,\(FWT\) 是用于解决对下标进行位运算卷积问题的方法. \(c_{i}=\sum_{i=j \oplus k} a_{j} b_{k} ...
- 快速沃尔什变换 FWT 学习笔记【多项式】
〇.前言 之前看到异或就担心是 FWT,然后才开始想别的. 这次学了 FWT 以后,以后判断应该就很快了吧? 参考资料 FWT 详解 知识点 by neither_nor 集训队论文 2015 集合幂 ...
- 快速沃尔什变换(FWT)学习笔记 + 洛谷P4717 [模板]
FWT求解的是一类问题:\( a[i] = \sum\limits_{j\bigoplus k=i}^{} b[j]*c[k] \) 其中,\( \bigoplus \) 可以是 or,and,xor ...
- 快速沃尔什变换(FWT)笔记
开头Orz hy,Orz yrx 部分转载自hy的博客 快速沃尔什变换,可以快速计算两个多项式的位运算卷积(即and,or和xor) 问题模型如下: 给出两个多项式$A(x)$,$B(x)$,求$C( ...
随机推荐
- php excel原理
- c#如何仅在datatgirdview控件的头部(列名处)添加右键菜单
近期在弄ArcgisAE实习,其中有一个功能是需要操作图层的属性字段的,为了方便操作图层的属性,最好是在图层的属性表中,也就是在显示图层属性的DataGirdView控件的头部添加一个右键菜单来实现相 ...
- 使用手机预览移动端项目(Vue)
1.在 npm run dev 启动Vue项目之后.例:http://localhost:8095/#/chatList 2.查看本机的 IP (WIN + R + cmd ) 输入 ipconfig ...
- @transient加在属性前的作用
我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable ...
- leetCode题解之First Missing Positive
1.问题描述 2.题解思路 本题的思路是对于数组中每个正的元素,应该将其放到数组中对应的位置,比如元素1 ,应该放在数组的第一个位置.以此类推,最后检查数组中元素值和下标不匹配的情况. 3.代码 in ...
- Object、T(以下代指泛型)、?的区别
因为最近看了很多项目底层都使用了T,?泛型,于是百度了一下有如下理解 我们先来试着理解一下Object类,学习Java的应该都知道Object是所有类的父类,注意:那么这就意味着它的范围非常广!首先记 ...
- d3js layout 深入理解
D3 layouts help you create more advanced visualisations such as treemaps: D3 layouts帮助您创造更加高级复杂的可视化图 ...
- Oracle 启用归档
[applprod@erp10 ~]$ watch ps -fu applprod[applprod@erp10 ~]$ kill -9 82902 84923 [applprod@erp10 ~]$ ...
- C++虚函数原理
类中的成员函数分为静态成员函数和非静态成员函数,而非静态成员函数又分为普通函数和虚函数. Q: 为什么使用虚函数 A: 使用虚函数,我们可以获得良好的可扩展性.在一个设计比较好的面向对象程序中,大多数 ...
- Intel Nehalem微架构Calpella平台机型Windows XP系统下如何开启AHCI硬盘工作模式(XP系统下如何加载AHCI驱动)
问题描述用户来电表示使用IDE模式安装XP系统后开启AHCI模式会出现开机蓝屏重启的问题,咨询如何在XP下加载AHCI驱动,以便开启BIOS中AHCI选项来发挥硬盘的最佳性能 问题分析 Windo ...