前言:

  $FWT$是用来处理位运算(异或、与、或)卷积的一种变换。位运算卷积是什么?形如$f[i]=\sum\limits_{j\oplus k==i}^{ }g[j]*h[k]$的卷积形式(其中$\oplus$为位运算)就是位运算卷积。如果暴力枚举的话,时间复杂度是$O(n^2)$,但运用$FWT$来解决就可达到$O(nlog_{n})$的时间复杂度。$FST$则是借助$FWT$来进行的对子集卷积的优化,相当于$FWT$的一个应用。

FWT

与卷积

对于与运算,有一个结论:$(i\&j)\&k==k<-->(i\&k==k)\&\&(j\&k==k)$。

那么我们就可以构造一个求父集和的函数$F(i)=\sum\limits_{j\&i==i}^{ }f(i)$,由此我们可以推出:

$G(k)*H(k)$

$=\sum\limits_{i\&k==k}^{ }g(i)\sum\limits_{j\&k==k}^{ }h(j)$

$=\sum\limits_{(i\&j)\&k==k}^{ }g(i)*h(j)$

$=\sum\limits_{t\&k==k}^{ }\sum\limits_{i\&j==t}^{ }g(i)*h(j)$

因为$f(t)=\sum\limits_{i\&j==t}^{ }g(i)*h(j)$,

所有上式$=\sum\limits_{t\&k==k}^{ }f(t)=F(k)$

因此我们只需要将$g,h$正变换成$G,H$,然后对应位相乘得到$F$后再将$F$逆变换回去即可得到$f$。

那么如何正变换?

以下面为例:

00 a

01 b

10 c

11 d

我们从最低位开始考虑,每次只考虑只有当前位不同的两个数之间的影响。显然求父集只有$1$会对$0$有贡献,因此我们将$01$的值加到$00$上,将$11$的值加到$10$上,再看下一位,同样将$11$的值加到$01$上,将$10$的值加到$00$上。这样最后$00$的值为$a+b+c+d$,$01$的值为$b+d$,$10$的值为$c+d$,$11$的值为$d$。同样逆变换就是将$1$的值从$0$上减掉即可。

附上代码

void fwt_and(int *a,int opt)
{
for(int k=2;k<=n;k<<=1)
{
for(int i=0,t=k>>1;i<n;i+=k)
{
for(int j=i;j<i+t;j++)
{
if(opt==1)
{
a[j]=(a[j]+a[j+t])%mod;
}
else
{
a[j]=(a[j]-a[j+t]+mod)%mod;
}
}
}
}
}

或卷积

或卷积和与卷积类似,对于或卷积同样有结论:$(i|j)|k==k<-->(i|k==k)\&\&(j|k==k)$

这次我们需要构造一个求子集和的函数$G(i)=\sum\limits_{j|i==i}^{ }g(j)$,推导过程和与卷积类似。

对于正变换,显然只有$0$对$1$有贡献;对于逆变换,只需要将$0$的值从$1$中减掉即可。

附上代码

void fwt_or(int *a,int opt)
{
for(int k=2;k<=n;k<<=1)
{
for(int i=0,t=k>>1;i<n;i+=k)
{
for(int j=i;j<i+t;j++)
{
if(opt==1)
{
a[j+t]=(a[j+t]+a[j])%mod;
}
else
{
a[j+t]=(a[j+t]-a[j]+mod)%mod;
}
}
}
}
}

异或卷积

对于异或卷积,我们设$bit(i)$代表$i$的二进制中$1$的奇偶性,因此有一个结论(这里异或用$\oplus$表示):$bit(i\&k)\oplus bit(j\&k)=bit((i\oplus j)\&k)$

对于原多项式$g$构造$G(i)=\sum\limits_{j=0}^{2^n-1}(-1)^{bit(j\&i)}g(j)$

开始推导:

$G(k)*H(k)$

$=\sum (-1)^{bit(i\&k)}g(i)\sum (-1)^{bit(j\&k)}h(j)$

$=\sum (-1)^{bit((i\oplus j)\& k)}g(i)*h(j)$

$=\sum (-1)^{bit(t\&k)}\sum\limits_{i\oplus j==t}^{ }g(i)*h(j)$

$=\sum (-1)^{bit(t\&k)}f(t)$

$=F(k)$

对于正变换,我们同样从最低位向最高位考虑,每次只考虑只有当前位不同的两个数之间的影响。对于每对$0$和$1$(设值分别为$a$和$b$),$0\&0=0$和$0\&1=0$都不会影响$bit$的值,所以$0$那个位置的值变成$a+b$;$1\&0=0$不会影响$bit$的值,但$1\&1=1$会影响$bit$的值(相当于在前面乘上一个$-1$的系数),因此$1$那个位置的值变成$a-b$。对于逆变换,相当于我们现在知道两个位置$x=a+b$,$y=a-b$,求$a$和$b$,可以得到$a=\frac{x+y}{2},b=\frac{x-y}{2}$。

附上代码

void fwt_xor(int *a,int opt)
{
int tmp;
for(int k=2;k<=n;k<<=1)
{
for(int i=0,t=k>>1;i<n;i+=k)
{
for(int j=i;j<i+t;j++)
{
tmp=a[j];
a[j]=(a[j]+a[j+t])%mod;
a[j+t]=(tmp-a[j+t]+mod)%mod;
if(opt==-1)
{
a[j]=1ll*a[j]*inv%mod;
a[j+t]=1ll*a[j+t]*inv%mod;
}
}
}
}
}

K进制异或卷积

可以发现二进制的异或运算相当于不进位加法即每一位对应相加后对$2$取模,而与运算相当于不进位乘法即每一位对应相乘后对$2$取模,$bit$相当于求二进制每一位的和对$2$取模。那么我们将这些在二进制下的运算扩展到$K$进制可以发现同样满足上述的结论,但对于从$g$求$G$的部分每个数前面的系数的底数是$-1$,显然这个系数不能扩展到$K$进制。那么我们现在就需要找一个系数$w$满足$w^0,w^1,w^2……w^{k-1}$都各不相同且$w^i=w^{i\%k}$。从$FFT$中我们知道了复数单位根这个东西,那么我们完全可以将$w$取$K$次单位根,这样就可以满足以上性质了!类比二进制亦或的正变换也可以得出$K$进制的正变换。

FST

$FST$通常用来优化一类子集$DP$,例如$f(S)=\sum g(T)*h(S-T)$,其中$T$是$S$的子集。

对于这个方程我们不能直接用$FWT$卷积,因为如果$g(i)*h(j)$会对$f(k)$有贡献就要求$i|j=k,i\&j=0$。

显然位运算卷积不能同时满足这两个要求,那么我们将方程变成二维表示$f[S][i]=\sum\limits_{j=1}^{i}\sum\limits_{a|b==S}^{ }g[a][j]*h[b][i-j]$

其中的第二维表示集合大小,对于$f[S][i]$只有当$i=|S|$时才有值,这样第一维保证并集为$S$,第二维保证交集为空集,所以其他不合法的状态不会影响答案。

这样我们就能对式子进行卷积:$F[S][i]=\sum\limits_{j=1}^{i}G[S][j]*H[S][i-j]$。求出每个$F$的值再$FWT$逆变换回去即可。

原题中的$f[S]$就是二维状态中的$f[S][|S|]$。

时间复杂度为$O(2^n*n^2)$。

快速沃尔什变换(FWT)及K进制异或卷积&快速子集变换(FST)讲解的更多相关文章

  1. 2019.7.3模拟 七星连珠(行列式+随机+k进制FWT)

    题目大意: 给一个\(n*n\)的矩阵,对于所有排列p,记录\(a[i][p[i]]\)的k进制下不进位加法的结果,问所有被记录过的数. \(n<=50,p=2.3,0<=a[i][j]& ...

  2. 快速沃尔什变换与k进制FWT

    这是一篇用来卖萌的文章QAQ 考虑以下三类卷积 \(C_k = \sum \limits_{i \;or\;j = k} A_i * B_j\) \(C_k = \sum \limits_{i\;an ...

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

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

  4. 快速沃尔什变换FWT

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

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

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

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

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

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

    [学习笔鸡]快速沃尔什变换FWT OR的FWT 快速解决: \[ C[i]=\sum_{j|k=i} A[j]B[k] \] FWT使得我们 \[ FWT(C)=FWT(A)*FWT(B) \] 其中 ...

  8. CF459C Pashmak and Buses (构造d位k进制数

    C - Pashmak and Buses Codeforces Round #261 (Div. 2) C. Pashmak and Buses time limit per test 1 seco ...

  9. P1066 2^k进制数

    传送门 题目描述 设r是个2^k 进制数,并满足以下条件: (1)r至少是个2位的2^k 进制数. (2)作为2^k 进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位. (3)将r转换为2进 ...

随机推荐

  1. Less与TypeScript的简单理解与应用,并使用WebPack打包静态页面

    既然选择了远方,便只顾风雨兼程 __ HANS许 系列:零基础搭建前后端分离项目 系列:零基础搭建前后端分离项目 创建空项目 使用Less 使用TypeScript 使用WebPack 开始写项目 总 ...

  2. Springboot整合activemq

    今天呢心血来潮,也有很多以前的学弟问到我关于消息队列的一些问题,有个刚入门,有的有问题都来问我,那么今天来说说如何快速入门mq. 一.首先说下什么是消息队列? 1.消息队列是在消息的传输过程中保存消息 ...

  3. 文本三剑客---awk(gawk)基础

    gawk程序是Unix中原始awk程序的GNU版本.gawk程序让流编辑器迈上了一个新的台阶,它提供了一种编程语言而不只是编辑器命令.在gawk编程语言中,可以完成下面的事情: (1)定义变量来保存数 ...

  4. http header Content-Type之常用三种

    Content-Type 用于指示资源的MIME类型 在响应头中,告诉客户端实际返回内容的类型 在请求头中,告诉服务器实际发送的数据类型 句法: Content-Type: text/html; ch ...

  5. 《全栈营销之如何制作个人博客》之二:php环境安装及个人博客后台搭建 让你的博客跑起来

    上一节我们讲了个人博客用什么开发语言,用什么CMS系统,从这一节我们就开始真正的干货,这一节我们讨论一下PHP环境的安装,及个人博客后台的搭建,让你的博客在正常的PHP环境中运行起来,你就可以进行后台 ...

  6. 用Gogs在Windows上搭建Git服务

    1.下载并安装Git,如有需求,请重启服务器让Path中的环境变量生效. 2.下载并安装Gogs,请注意,在Windows中部署时,请下载MiniWinService(mws)版本. 3.在Maria ...

  7. java压缩指定目录下的所有文件和文件夹的代码

    将代码过程较好的代码段备份一下,下边资料是关于java压缩指定目录下的所有文件和文件夹的代码,希望对码农有帮助. String sourceDir="E:\test";int pa ...

  8. Java:API文档;文档注释中的javadoc标记;官方API;自己动手给项目建一个API文档

    1.什么是API文档 在Java语言中有3种注释 //单行注释 /* 多行注释 */ /** * 文档注释 */ API(应用程序接口)文档就是用javadoc命令提取文档注释生成的,html格式,用 ...

  9. 扫码下单与ERP客户端锁桌功能FAQ

    一.需求场景:因为目前客户端和平台端有两套数据库,两套数据库通过网络交互信息,且双方都可以发起支付,这种结构容易造成: 1.一笔订单同时支付.一笔订单支付时未按最新订单进行支付,支付多付.支付少付的情 ...

  10. 【视频】设计模式(Java)视频讲解

    设计模式(JAVA) 视频网址: http://www.qghkt.com/ 设计模式(JAVA)视频地址: https://ke.qq.com/course/318643?tuin=a508ea62 ...