tokenpocket钱包官网客服|fwt是什么意思

作者: tokenpocket钱包官网客服
2024-03-16 08:58:49

FWT 定义: 联邦的预缴税金 - Federal Withholding Tax

FWT 定义: 联邦的预缴税金 - Federal Withholding Tax

↓ 跳到主内容

EnglishالعربيةБългарскиCatalàČeštinaCymraegDanskDeutschΕλληνικάEspañolEestiفارسیSuomiFrançaisעִבְרִיתहिन्दीJezikAyititMagyarBahasa IndonesiaItaliano日本語한국어LietuviųLatviešuMelayuMaltiNorskNederlandsPolskiPortuguêsRomânăРусскийSlovenčinaslovenščinaSvenskaไทยTürkçeукраїнськаاردوViệt Nam繁體中文

首页 › 3 个字母 › FWT › 联邦的预缴税金

FWT: 联邦的预缴税金

FWT是什么意思? 以上是FWT含义之一。 您可以下载下面的图像打印或通过Twitter,Facebook,Google或Pinterest与您的朋友分享。 如果您是网站管理员或博主,请随时在您的网站上发布该图片。FWT可能有其他定义。 请向下滚动以查看其英文定义,以及您所用语言的其他五种含义。

FWT的含义

下图显示了英语中FWT的定义之一。您可以下载PNG格式的图像文件以供离线使用,或通过电子邮件将FWT定义的图像发送给您的朋友。

FWT的其他含义

如上所述,FWT具有其他含义。请注意下面列出了其他五个含义。您可以单击左侧的链接以查看每个定义的详细信息,包括英语和您的本地语言的定义。

在英语中的定义:Federal Withholding Tax

FWT 此外代表:完整的病房测试最后的预缴税金公平磨损 & 撕裂淡水舱固定的无线电话机......更多

‹ 主管的造船纽波特纽斯

发展经济学年度银行会议 ›

语言

EnglishالعربيةБългарскиCatalàČeštinaCymraegDanskDeutschΕλληνικάEspañolEestiفارسیSuomiFrançaisעִבְרִיתहिन्दीJezikAyititMagyarBahasa IndonesiaItaliano日本語한국어LietuviųLatviešuMelayuMaltiNorskNederlandsPolskiPortuguêsRomânăРусскийSlovenčinaslovenščinaSvenskaไทยTürkçeукраїнськаاردوViệt Nam繁體中文

简体中文

Recent Posts

文章分类  

>>   

1   

2   

3   

4   

5   

6   

7   

8   

9   

10   

A   

B   

C   

D   

E   

F   

G   

H   

I   

J   

K   

L   

M   

N   

O   

P   

Q   

R   

S   

T   

U   

V   

W   

X   

Y   

Z   

© 2014 - 2023

Abbreviation Finder. 站点地图 | Recent Posts

Terms of Use | Privacy Policy | About Us | Blog

FWT(快速沃尔什变换)零基础详解qaq(ACM/OI) - 知乎

FWT(快速沃尔什变换)零基础详解qaq(ACM/OI) - 知乎首发于桃酱的算法笔记切换模式写文章登录/注册FWT(快速沃尔什变换)零基础详解qaq(ACM/OI)月下桃子树君がそれでいいなら僕だってそれで構わないさ。1.前言(废话)记得一年半之前做SRM518 Nim的时候还不知道FWT,当时自己用分治完美的水过去了。然后昨天的牛客有一道题,是说nim博弈中有n堆石子,请问最多取出多少堆石子可以让先手必败。当时竟然没思路QAQ???想了想使劲往字典树靠边靠不上去QAQ,然后就没想出来!!!想当年自己手推FWT或运算,真的感叹岁月是把杀猪刀!于是怒写这篇博客QAQ把这个算法总结一下QAQ(其实我觉得这变换竟然也有名字真的很神奇QAQ)2.FWT简介沃尔什转换(Walsh Transform)是在频谱分析上作为离散傅立叶变换的替代方案的一种方法。 ——wiki百科其实这个变换在信号处理中应用很广泛,fft是double类型的,但是walsh把信号在不同震荡频率方波下拆解,因此所有的系数都是绝对值大小相同的整数,这使得不需要作浮点数的乘法运算,提高了运算速度。所以,FWT和FFT的核心思想应该是相同的。都是对数组的变换。我们设数组A经过快速沃尔什变换之后记作那么FWT核心思想就是:我们需要一个新序列C,由序列A和序列B经过某运算规则得到,即。我们先正向得到,然后根据(*为点乘),在O(n)求出,然后再逆向运算得到原序列C。 时间复杂度为在算法竞赛中,FWT是用于解决对下标进行位运算卷积问题的方法。公式:其中是任意二元位运算中的某一种,就是普通乘法。3.FWT的运算3.1FWT之与(&)运算和或(|)运算与运算和或运算的本质是差不多的,所以这里讲一下或运算,与运算也是可以自己根据公式yy出来的。3.1.1或运算如果有,那么i的二进制位为1的位置和j的二进制位为1的位置肯定是k的二进制位为1的位置的子集。现在要得到,我们就要构造这个fwt的规则。我们按照定义,显然可以构造,表示j满足二进制中1为i的子集。那么显然会有即那么我们接下来看怎么求。首先肯定不能枚举了,复杂度为n^2。既然不能整体枚举,我们就考虑分治。我们把整个区间二分,其实二分区间之后,下标写成二进制形式是有规律可循的。我们令表示A的前一半,表示区间的后一半,那么A0就是A下标最大值的最高位为0,他的子集就是他本身的子集(因为最高位为0了),但是A1的最高位是1,他满足条件的子集不仅仅是他本身,还包最高位为0的子集,即其中merge表示向字符串拼接一样把他们拼起来。+就是普通加法,表示对应二进制位相加。这样我们就通过二分能在logn完成拼接,每次拼接的时候要完成一次运算,也就是说在的时间复杂度得到了接下来就是反演了,其实反演是很简单的,既然知道了A0的本身的子集是他自己(A0 = FAT[A0]),A1的子集是 FAT[A0] + FAT[A1](A1' = A0' + A1'),那就很简单的得出反演的递推式了3.1.2与运算与运算类比或运算可以得到类似结论3.2异或运算最常考的异或运算。异或的卷积是基于如下原理:若我们令i&j中1数量的奇偶性为i与j的奇偶性,那么i与k的奇偶性异或j和k的奇偶性等于i^j和k的奇偶性。对于的运算其实也很好得到。公式如下(C1表示i&j奇偶性为0,C2表示i&j的奇偶性为1)结论3.3 同或运算类比异或运算给出公式:(C1表示i|j奇偶性为0,C2表示i|j的奇偶性为1)QAQ编辑于 2018-08-12 19:35算法竞赛OI(信息学奥林匹克)ACM​赞同 325​​28 条评论​分享​喜欢​收藏​申请转载​文章被以下专栏收录桃酱的算法笔记ACMer的自我成长笔记。多为算法学习

FWT快速沃尔什变换学习笔记 - 小蒟蒻yyb - 博客园

FWT快速沃尔什变换学习笔记 - 小蒟蒻yyb - 博客园

会员

周边

新闻

博问

AI培训

云市场

所有博客

当前博客

我的博客

我的园子

账号设置

简洁模式 ...

退出登录

注册

登录

小蒟蒻yyb的博客

AFO

博客园

首页

新随笔

联系

订阅

管理

FWT快速沃尔什变换学习笔记

FWT快速沃尔什变换学习笔记

1、FWT用来干啥啊

回忆一下多项式的卷积\(C_k=\sum_{i+j=k}A_i*B_j\)

我们可以用\(FFT\)来做。

甚至在一些特殊情况下,我们\(C_k=\sum_{i*j=k}A_i*B_j\)也能做(SDOI2015 序列统计)。

但是,如果我们把操作符换一下呢?

比如这样?

\(C_k=\sum_{i|j=k}A_i*B_j\)

\(C_k=\sum_{i\&j=k}A_i*B_j\)

\(C_k=\sum_{i\wedge j=k}A_i*B_j\)

似乎这就不能用\(FFT\)来做了。

这样子就有了\(FWT\)——用来解决多项式的位运算卷积

2、FWT大概要怎么搞啊

我们想一想\(FFT\)在干啥?

先对于一个多项式求出他在若干个单位根的点值表示法

再将多项式乘起来,最后再复原。

那么,我们可不可以用一个类似的思路呢?

先将多项式求出另外一个多项式\(FWT(A)\),再将对应的位置乘起来,最后再复原?

也就是\(FWT(C)=FWT(A)*FWT(B)\)(这个不是卷积,是对应位置相乘)?

废话,显然可以,要不然我还写什么\(FWT\)呢?

我们先来一点奇奇怪怪的记号吧。

因为多项式可以看成一个\(n\)维向量

所以,我们定义以下东西:

\(A+B=(A_0+B_0,A_1+B_1,......)\)

\(A-B=(A_0-B_0,A_1-B_1,......)\)

\(A\oplus B=(\sum_{i\oplus j=0}A_i*B_j,\sum_{i\oplus j=1}A_i*B_j,......)\)

3、或(or)卷积

或卷积长成这个样子:\(C_k=\sum_{i|j=k}A_i*B_j\)

写成向量的形式也就是这样子:\(A|B=(\sum_{i|j=0}A_i*B_j,\sum_{i|j=1}A_i*B_j,......)\)

很显然的一点:这个东西满足交换律,也就是\(A|B=B|A\)

再来仔细的看看,这个东西也满足结合律。

简单的证明一下\((A+B)|C=(\sum_{i|j=0}(A_i+B_i)*C_j,......)\)

很明显可以把括号拆开,然后分成两个\(\sum\),也就是\(A|C+B|C\)

我们这样子定义一下:

对于一个多项式\(A\)(最高次项是\(2^n\)),

我们把它分成两部分\(A_0,A_1\),分别表示前\(2^{n-1}\)次项和后面的\(2^{n-1}\)次项

也就是最高位为\(0\)与\(1\)的两部分。

对于或卷积,我们有:

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

\]对于\(n=0\)的时候,这个是非常显然的(常数还不显然了。。。)

啥?你问打个括号,然后中间一个逗号是啥意思?

不是说了这个结果是一个\(2^n\)维向量?

也就表示前\(2^{n-1}\)项是逗号前面的东西,后面那几项是逗号后面的东西

完全可以理解为将两个多项式强行前后拼接成一个新的多项式。

好的,我们来伪证(感性理解)一下\(n>0\)的时候的式子

对于\(A_0\)中的任意一项,如果在做\(or\)卷积的时候,和任意一个\(A_1\)中的项\(or\)了一下

那么它的首位一定是\(1\),必定不会对于\(FWT(A_0)\)产生任何贡献,

所以\(FWT(A)\)的前\(2^{n-1}\)项一定等于\(FWT(A_0)\)。

后面这个东西看起来就很不好证明了,所以我们先考虑证明点别的东西。

\(FWT(A+B)=FWT(A)+FWT(B)\)

证明(伪):

对于一个多项式\(A\)的\(FWT(A)\),它一定只是若干个原多项式中的若干项的若干倍的和。

即\(FWT(A)\)一定不包含原多项式的某几项的乘积。

如果包含了原多项式的乘积,那么在求出卷积之后,

我们发现此时的结果与某个多项式自身的某两项的乘积有关

但是我们在或卷积的结果式中发现一定只与某个多项式的某一项与另一个多项式的某一项有关。

因此,我们知道\(FWT(A)\)的任意一项只与\(A\)的某几项的和有关

因此,我们这个式子可以这样拆开。

此时,这个伪证成立。(这话怎么这么别扭)

但是怎么说,总是感觉证明后面都要贴上一个伪字,

如果我们能够知道\(FWT(A)\)是个啥东西,我们就可以把这个字给扔掉了

先给出结论:

对于\(or\)卷积而言,\(FWT(A)[i]=\sum_{j|i=i}A[j]\)

它基于的原理呢?

如果\(i|k=k,j|k=k\),那么就有\((i|j)|k=k\)

这样说很不清楚,我们现在来证明后半部分为啥是\(FWT(A_0+A_1)\)

因为\(A_0\)中取一项和\(A_1\)中取一项做\(or\)卷积,显然贡献会产生到\(A_1\)中去

首先,对于\(A_1\)中的任意两项的贡献,一定在\(A_1\)中,即使去掉了最高位,此时也会产生这部分的贡献

但是现在在合并\(A_0\)和\(A_1\)的贡献的时候,还需要考虑\(A_0\)的贡献

相当于只丢掉了最高位,因此,在\(A_0\)与\(A_1\)对应项的\(FWT\)的和就是我们现在合并之后的结果

所以也就是\(FWT(A_0+A_1)=FWT(A_0)+FWT(A_1)\)

这样子,我们来考虑或卷积,也就是\(FWT(A|B)\)

我们要证明它等于\(FWT(A)\times FWT(B)\),这样子我们就可以放心的使用\(or\)卷积了

证明:

\[\begin{aligned}

FWT(A|B)=&FWT((A|B)_0,(A|B)_1)\\

=&FWT(A_0|B_0,A_0|B_1+A_1|B_0+A_1|B_1)\\

=&(FWT(A_0|B_0),FWT(A_0|B_0+A_0|B_1+A_1|B_0+A_1|B_1))\\

=&(FWT(A_0)\times FWT(B_0)\\&,FWT(A_0)\times FWT(B_0)+FWT(A_0)\times FWT(B_1)+FWT(A_1)\times FWT(B_0)+FWT(A_1)\times FWT(B_1))\\

=&(FWT(A_0)\times FWT(B_0),(FWT(A_0)+FWT(A_1))\times (FWT(B_0)+FWT(B_1)))\\

=&(FWT(A_0),FWT(A_0+A_1))\times (FWT(B_0),FWT(B_0+B_1))\\

=&FWT(A)\times FWT(B)

\end{aligned}

\]这是一个数学归纳法的证明,请仔细看一看QwQ

当只有一项的时候这个是显然的。

好啦,这样就证明出了\(or\)卷积的正确性了

4、和(and)卷积

\(and\)卷积是这样的:\(C_k=\sum_{i\&j=k}A_i*B_j\)

写成向量的形式:\(A\&B=(\sum_{i\&j=0}A_i*B_j,\sum_{i\&j=1}A_i*B_j,......)\)

交换律?\(A\&B=B\&A\)显然成立

结合律?和前面一样是满足的。

好的,先把变换的式子写出来。

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

\]从某种意义上来说,\(and\)和\(or\)和很类似的。

我们这样看:

\(0|0=0,0|1=1,1|0=1,1|1=1\)

\(0\&0=0,0\&1=0,1\&0=0,1\&1=1\)

都是\(3\)个\(0/1\),然后剩下的那个只有一个

既然如此,其实我们也可以用\(or\)卷积类似的东西很容易的证明\(and\)卷积

\(FWT(A+B)=FWT(A)+FWT(B)\)

大致的伪证就是\(FWT(A)\)是关于\(A\)中元素的一个线性组合,显然满足分配率

接着只要再证明

\(FWT(A)\times FWT(B)=FWT(A\&B)\)就行了

方法仍然是数学归纳法。

证明:

\[\begin{aligned}

FWT(A\&B)=&FWT((A\&B)_0,(A\&B)_1)\\

=&FWT(A_0\&B_0+A_0\&B_1+A_1\&B_0,A_1\&B_1)\\

=&(FWT(A_0\&B_0+A_0\&B_1+A_1\&B_0+A_1\&B_1),FWT(A_1\&B_1))\\

=&((FWT(A_0)+FWT(A_1))\times (FWT(B_0)+FWT(B_1)),FWT(A_1)*FWT(B_1))\\

=&(FWT(A_0+A_1),FWT(A_1))\times (FWT(B_0+B_1),FWT(B_1))\\

=&FWT(A)\times FWT(B)

\end{aligned}

\]好啦,这样子\(and\)卷积就证明完啦。

5、异或(xor)卷积

为了方便打,我就把异或操作用\(\oplus\)来表示吧(而且这样似乎也是一种常用的表达方式)

主要原因是\(\wedge\)太难打了

表达式:\(C_k=\sum_{i\oplus j=k}A_i*B_j\)

向量式按照上面写就行了

先写一下\(FWT(A)\)吧

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

\]

\(FWT(A+B)=FWT(A)+FWT(B)\)

这个显然还是成立的,理由和上面是一样的。

接下来还是证明相同的东西

\(FWT(A)\times FWT(B)=FWT(A\oplus B)\)

证明:

\[\begin{aligned}

FWT(A\oplus B)=&(FWT(A\oplus B)_0+FWT(A\oplus B)_1,FWT(A\oplus B)_0-FWT(A\oplus B)_1)\\

=&(FWT(A_0\oplus B_0+A_1\oplus B_1+A_1\oplus B_0+A_0\oplus B_1)\\&,FWT(A_0\oplus B_0+A_1\oplus B_1-A_1\oplus B_0-A_0\oplus B_1))\\

=&((FWT(A_0)+FWT(A_1))\times(FWT(B_0)+FWT(B_1))\\

&,(FWT(A_0)-FWT(A_1))\times(FWT(B_0)-FWT(B_1))\\

=&(FWT(A_0+A_1)\times(B_0+B_1),FWT(A_0-A_1)\times FWT(B_0-B_1))\\

=&(FWT(A_0+A_1),FWT(A_0-A_1))\times(FWT(B_0+B_1),FWT(B_0-B_1))\\

=&FWT(A)\times FWT(B)

\end{aligned}

\]好啦好啦

这样子\(xor\)卷积也证明完啦。

于是我们可以开心的来写\(FWT\)啦

6、IFWT

我们现在可以在\(O(nlogn)\)的时间复杂度里面得到\(FWT(A\oplus B)\),其中\(\oplus\)表示一个位运算。

得到了\(FWT\)之后我们需要还原这个数组,也就是\(IFWT\)(叫\(UFWT\)也没啥问题??)

怎么求?

正向的过程我们知道了,逆向的反着做啊。

所以:

\(or\)卷积:$$IFWT(A)=(IFWT(A_0),IFWT(A_1)-IFWT(A_0))$$

\(and\)卷积:$$IFWT(A)=(IFWT(A_0)-IFWT(A_1),IFWT(A_1))$$

\(xor\)卷积:$$IFWT(A)=(\frac{IFWT(A_0)+IFWT(A_1)}{2},\frac{IFWT(A_0)-IFWT(A_1)}{2})$$

7、代码实现

\(or\)卷积的代码

void FWT(ll *P,int opt)

{

for(int i=2;i<=N;i<<=1)

for(int p=i>>1,j=0;j

for(int k=j;k

P[k+p]+=P[k]*opt;

}

\(and\)卷积只需要在\(or\)卷积的基础上修改一点点就好了

void FWT(ll *P,int opt)

{

for(int i=2;i<=N;i<<=1)

for(int p=i>>1,j=0;j

for(int k=j;k

P[k]+=P[k+p]*opt;

}

\(xor\)卷积其实也差不多(这个是在模意义下的\(FWT\))

如果不是在模意义下的话,开一个\(long\ long\),然后把逆元变成直接除二就好了。

void FWT(int *P,int opt)

{

for(int i=2;i<=N;i<<=1)

for(int p=i>>1,j=0;j

for(int k=j;k

{

int x=P[k],y=P[k+p];

P[k]=(x+y)%MOD;P[k+p]=(x-y+MOD)%MOD;

if(opt==-1)P[k]=1ll*P[k]*inv2%MOD,P[k+p]=1ll*P[k+p]*inv2%MOD;

}

}

Upd:

写了个好看点的板子,这样就和\(FFT\)长得很像了。

void FWT_or(int *a,int opt)

{

for(int i=1;i

for(int p=i<<1,j=0;j

for(int k=0;k

if(opt==1)a[i+j+k]=(a[j+k]+a[i+j+k])%MOD;

else a[i+j+k]=(a[i+j+k]+MOD-a[j+k])%MOD;

}

void FWT_and(int *a,int opt)

{

for(int i=1;i

for(int p=i<<1,j=0;j

for(int k=0;k

if(opt==1)a[j+k]=(a[j+k]+a[i+j+k])%MOD;

else a[j+k]=(a[j+k]+MOD-a[i+j+k])%MOD;

}

void FWT_xor(int *a,int opt)

{

for(int i=1;i

for(int p=i<<1,j=0;j

for(int k=0;k

{

int X=a[j+k],Y=a[i+j+k];

a[j+k]=(X+Y)%MOD;a[i+j+k]=(X+MOD-Y)%MOD;

if(opt==-1)a[j+k]=1ll*a[j+k]*inv2%MOD,a[i+j+k]=1ll*a[i+j+k]*inv2%MOD;

}

}

posted @

2018-05-21 08:53 

小蒟蒻yyb 

阅读(23374) 

评论(44) 

编辑 

收藏 

举报

会员力量,点亮园子希望

刷新页面返回顶部

公告

Copyright © 2024 小蒟蒻yyb

Powered by .NET 8.0 on Kubernetes

FWT是什么意思? - FWT的全称 | 在线英文缩略词查询

FWT是什么意思? - FWT的全称 | 在线英文缩略词查询

↓ 跳到主内容

EnglishالعربيةБългарскиCatalàČeštinaCymraegDanskDeutschΕλληνικάEspañolEestiفارسیSuomiFrançaisעִבְרִיתहिन्दीJezikAyititMagyarBahasa IndonesiaItaliano日本語한국어LietuviųLatviešuMelayuMaltiNorskNederlandsPolskiPortuguêsRomânăРусскийSlovenčinaslovenščinaSvenskaไทยTürkçeукраїнськаاردوViệt Nam繁體中文

首页 › 3 个字母 › FWT

FWT 是什么意思?

你在寻找FWT的含义吗?在下图中,您可以看到FWT的主要定义。 如果需要,您还可以下载要打印的图像文件,或者您可以通过Facebook,Twitter,Pinterest,Google等与您的朋友分享。要查看FWT的所有含义,请向下滚动。 完整的定义列表按字母顺序显示在下表中。

FWT的主要含义

下图显示了FWT最常用的含义。 您可以将图像文件下载为PNG格式以供离线使用,或通过电子邮件发送给您的朋友。如果您是非商业网站的网站管理员,请随时在您的网站上发布FWT定义的图像。

FWT的所有定义

如上所述,您将在下表中看到FWT的所有含义。 请注意,所有定义都按字母顺序列出。您可以单击右侧的链接以查看每个定义的详细信息,包括英语和您当地语言的定义。

首字母缩写词定义FWT公平磨损 & 撕裂FWT固定的无线电话机FWT完整的病房测试FWT家族肾母细胞瘤FWT快速小波变换FWT最后的预缴税金FWT林业和木材的技术FWT法国的冬天的时候FWT淡水舱FWT联邦的预缴税金FWT聚焦的波技术FWT飞行适应性试验

‹ IRSA

KHNH ›

语言

EnglishالعربيةБългарскиCatalàČeštinaCymraegDanskDeutschΕλληνικάEspañolEestiفارسیSuomiFrançaisעִבְרִיתहिन्दीJezikAyititMagyarBahasa IndonesiaItaliano日本語한국어LietuviųLatviešuMelayuMaltiNorskNederlandsPolskiPortuguêsRomânăРусскийSlovenčinaslovenščinaSvenskaไทยTürkçeукраїнськаاردوViệt Nam繁體中文

简体中文

Recent Posts

文章分类  

>>   

1   

2   

3   

4   

5   

6   

7   

8   

9   

10   

A   

B   

C   

D   

E   

F   

G   

H   

I   

J   

K   

L   

M   

N   

O   

P   

Q   

R   

S   

T   

U   

V   

W   

X   

Y   

Z   

© 2014 - 2023

Abbreviation Finder. 站点地图 | Recent Posts

Terms of Use | Privacy Policy | About Us | Blog

快速沃尔什变换 - OI Wiki

什变换 - OI Wiki 跳转至 OI Wiki 快速沃尔什变换 正在初始化搜索引擎 OI-wiki/OI-wiki 简介 比赛相关 工具软件 语言基础 算法基础 搜索 动态规划 字符串 数学 数据结构 图论 计算几何 杂项 专题 关于 Hulu OI Wiki OI-wiki/OI-wiki 简介 简介 Getting Started 关于本项目 如何参与 OI Wiki 不是什么 格式手册 数学符号表 F.A.Q. 用 Docker 部署 OI Wiki 镜像站列表 致谢 比赛相关 比赛相关 比赛相关简介 赛事 赛事 OI 赛事与赛制 ICPC/CCPC 赛事与赛制 题型 题型 题型概述 交互题 学习路线 学习资源 技巧 技巧 读入、输出优化 分段打表 常见错误 常见技巧 出题 工具软件 工具软件 工具软件简介 代码编辑工具 代码编辑工具 Vim Emacs VS Code Atom Eclipse Notepad++ Kate Dev-C++ CLion Geany Xcode GUIDE Sublime Text CP Editor 评测工具 评测工具 评测工具简介 Arbiter Cena CCR Plus Lemon 命令行 编译器 WSL (Windows 10) Special Judge Testlib Testlib Testlib 简介 通用 Generator Validator Interactor Checker Polygon OJ 工具 LaTeX 入门 Git 语言基础 语言基础 语言基础简介 C++ 基础 C++ 基础 Hello, World! C++ 语法基础 变量 运算 流程控制语句 流程控制语句 分支 循环 高级数据类型 高级数据类型 数组 结构体 联合体 指针 函数 文件操作 C++ 标准库 C++ 标准库 C++ 标准库简介 STL 容器 STL 容器 STL 容器简介 迭代器 序列式容器 关联式容器 无序关联式容器 容器适配器 STL 算法 bitset string pair C++ 进阶 C++ 进阶 类 命名空间 值类别 重载运算符 引用 常值 新版 C++ 特性 Lambda 表达式 pb_ds pb_ds pb_ds 简介 堆 平衡树 编译优化 C++ 与其他常用语言的区别 Pascal 转 C++ 急救 Python 速成 Java 速成 Java 进阶 算法基础 算法基础 算法基础简介 复杂度 枚举 模拟 递归 & 分治 贪心 排序 排序 排序简介 选择排序 冒泡排序 插入排序 计数排序 基数排序 快速排序 归并排序 堆排序 桶排序 希尔排序 锦标赛排序 tim排序 排序相关 STL 排序应用 前缀和 & 差分 二分 倍增 构造 搜索 搜索 搜索部分简介 DFS(搜索) BFS(搜索) 双向搜索 启发式搜索 A* 迭代加深搜索 IDA* 回溯法 Dancing Links Alpha-Beta 剪枝 优化 动态规划 动态规划 动态规划部分简介 动态规划基础 记忆化搜索 背包 DP 区间 DP DAG 上的 DP 树形 DP 状压 DP 数位 DP 插头 DP 计数 DP 动态 DP 概率 DP DP 优化 DP 优化 单调队列/单调栈优化 斜率优化 四边形不等式优化 状态设计优化 其它 DP 方法 字符串 字符串 字符串部分简介 字符串基础 标准库 字符串匹配 字符串哈希 字典树 (Trie) 前缀函数与 KMP 算法 Boyer–Moore 算法 Z 函数(扩展 KMP) 自动机 AC 自动机 后缀数组 (SA) 后缀数组 (SA) 后缀数组简介 最优原地后缀排序算法 后缀自动机 (SAM) 后缀平衡树 广义后缀自动机 后缀树 Manacher 回文树 序列自动机 最小表示法 Lyndon 分解 Main–Lorentz 算法 数学 数学 数学部分简介 符号 进位制 位运算 二进制集合操作 平衡三进制 高精度计算 快速幂 置换和排列 弧度制与坐标系 复数 数论 数论 数论基础 素数 最大公约数 数论分块 欧拉函数 筛法 Meissel–Lehmer 算法 分解质因数 裴蜀定理 类欧几里德算法 欧拉定理 & 费马小定理 乘法逆元 线性同余方程 中国剩余定理 升幂引理 威尔逊定理 卢卡斯定理 同余方程 二次剩余 原根 离散对数 剩余 莫比乌斯反演 杜教筛 Powerful Number 筛 Min_25 筛 洲阁筛 连分数 Stern–Brocot 树与 Farey 序列 二次域 循环连分数 Pell 方程 多项式与生成函数 多项式与生成函数 多项式与生成函数简介 代数基本定理 快速傅里叶变换 快速数论变换 快速沃尔什变换 快速沃尔什变换 目录 简介 FWT 的运算 FWT 之与(&)运算和或(|)运算 或运算 与运算 异或运算 同或运算 例题 Chirp Z 变换 多项式牛顿迭代 多项式多点求值|快速插值 多项式初等函数 常系数齐次线性递推 多项式平移|连续点值平移 符号化方法 普通生成函数 指数生成函数 狄利克雷生成函数 组合数学 组合数学 排列组合 抽屉原理 容斥原理 康托展开 斐波那契数列 错位排列 卡特兰数 斯特林数 贝尔数 伯努利数 Entringer Number Eulerian Number 分拆数 范德蒙德卷积 图论计数 线性代数 线性代数 线性代数简介 向量 内积和外积 矩阵 初等变换 行列式 线性空间 线性基 线性映射 特征多项式 对角化 Jordan标准型 线性规划 线性规划 线性规划简介 单纯形算法 群论 群论 群论简介 置换群 概率论 概率论 基本概念 条件概率与独立性 随机变量 随机变量的数字特征 概率不等式 博弈论 博弈论 博弈论简介 公平组合游戏 非公平组合游戏 反常游戏 数值算法 数值算法 插值 数值积分 高斯消元 牛顿迭代法 傅里叶-莫茨金消元法 序理论 杨氏矩阵 Schreier–Sims 算法 Berlekamp–Massey 算法 数据结构 数据结构 数据结构部分简介 栈 队列 链表 哈希表 并查集 并查集 并查集 并查集复杂度 堆 堆 堆简介 二叉堆 配对堆 左偏树 块状数据结构 块状数据结构 分块思想 块状数组 块状链表 树分块 Sqrt Tree 单调栈 单调队列 ST 表 树状数组 线段树 李超线段树 区间最值操作 & 区间历史最值 划分树 二叉搜索树 & 平衡树 二叉搜索树 & 平衡树 二叉搜索树 & 平衡树 Treap Splay 树 WBLT Size Balanced Tree AVL 树 B 树 B+ 树 替罪羊树 Leafy Tree 笛卡尔树 红黑树 左偏红黑树 AA 树 2-3 树 2-3-4 树 跳表 可持久化数据结构 可持久化数据结构 可持久化数据结构简介 可持久化线段树 可持久化块状数组 可持久化平衡树 可持久化字典树 可持久化可并堆 树套树 树套树 线段树套线段树 平衡树套线段树 线段树套平衡树 树状数组套权值线段树 分块套树状数组 K-D Tree 动态树 动态树 Link Cut Tree 全局平衡二叉树 Euler Tour Tree Top Tree 析合树 PQ 树 手指树 霍夫曼树 图论 图论 图论部分简介 图论相关概念 图的存储 DFS(图论) BFS(图论) 树上问题 树上问题 树基础 树的直径 最近公共祖先 树的重心 树链剖分 树上启发式合并 虚树 树分治 动态树分治 AHU 算法 树哈希 树上随机游走 矩阵树定理 有向无环图 拓扑排序 最小生成树 斯坦纳树 最小树形图 最小直径生成树 最短路 拆点 差分约束 k 短路 同余最短路 连通性相关 连通性相关 强连通分量 双连通分量 割点和桥 圆方树 点/边连通度 环计数问题 2-SAT 欧拉图 哈密顿图 二分图 最小环 平面图 图的着色 网络流 网络流 网络流简介 最大流 最小割 费用流 上下界网络流 Stoer–Wagner 算法 图的匹配 图的匹配 图匹配 增广路 二分图最大匹配 二分图最大权匹配 一般图最大匹配 一般图最大权匹配 Prüfer 序列 LGV 引理 弦图 最大团搜索算法 支配树 图上随机游走 计算几何 计算几何 计算几何部分简介 二维计算几何基础 三维计算几何基础 距离 Pick 定理 三角剖分 凸包 扫描线 旋转卡壳 半平面交 平面最近点对 随机增量法 反演变换 计算几何杂项 杂项 杂项 杂项简介 离散化 双指针 离线算法 离线算法 离线算法简介 CDQ 分治 整体二分 莫队算法 莫队算法 莫队算法简介 普通莫队算法 带修改莫队 树上莫队 回滚莫队 二维莫队 莫队二次离线 莫队配合 bitset 分数规划 随机化 随机化 随机函数 随机化技巧 爬山算法 模拟退火 悬线法 计算理论基础 字节顺序 约瑟夫问题 格雷码 表达式求值 在一台机器上规划任务 主元素问题 Garsia–Wachs 算法 15-puzzle Kahan 求和 珂朵莉树/颜色段均摊 专题 专题 RMQ 并查集应用 括号序列 线段树与离线询问 关于 Hulu 关于 Hulu 关于 Hulu 目录 简介 FWT 的运算 FWT 之与(&)运算和或(|)运算 或运算 与运算 异或运算 同或运算 例题 快速沃尔什变换(本文转载自 桃酱的算法笔记,原文戳 链接,已获得作者授权)简介沃尔什转换(Walsh Transform)是在频谱分析上作为离散傅立叶变换的替代方案的一种方法。——维基百科其实这个变换在信号处理中应用很广泛,fft 是 double 类型的,但是 walsh 把信号在不同震荡频率方波下拆解,因此所有的系数都是绝对值大小相同的整数,这使得不需要作浮点数的乘法运算,提高了运算速度。所以,FWT 和 FFT 的核心思想应该是相同的,都是对数组的变换。我们记对数组 进行快速沃尔什变换后得到的结果为 。那么 FWT 核心思想就是:我们需要一个新序列 ,由序列 和序列 经过某运算规则得到,即 ;我们先正向得到 ,再根据 在 的时间复杂度内求出 ;然后逆向运算得到原序列 。时间复杂度为 。在算法竞赛中,FWT 是用于解决对下标进行位运算卷积问题的方法。公式:(其中 是二元位运算中的某一种, 是普通乘法)FWT 的运算FWT 之与(&)运算和或(|)运算与运算和或运算的本质是差不多的,所以这里讲一下或运算,与运算也是可以自己根据公式 yy 出来的。或运算如果有 ,那么 的二进制位为 的位置和 的二进制位为 的位置肯定是 的二进制位为 的位置的子集。现在要得到 ,我们就要构造这个 fwt 的规则。我们按照定义,显然可以构造 ,来表示 满足二进制中 为 的子集。那么显然会有 那么我们接下来看 怎么求。首先肯定不能枚举了,复杂度为 。既然不能整体枚举,我们就考虑分治。我们把整个区间二分,其实二分区间之后,下标写成二进制形式是有规律可循的。我们令 表示 的前一半, 表示区间的后一半,那么 就是 A 下标最大值的最高位为 ,他的子集就是他本身的子集(因为最高位为 了),但是 的最高位是 ,他满足条件的子集不仅仅是他本身,还包最高位为 的子集,即其中 merge 表示像字符串拼接一样把它们拼起来, 就是普通加法,表示对应二进制位相加。这样我们就通过二分能在 的时间复杂度内完成拼接,每次拼接的时候要完成一次运算,也就是说在 的时间复杂度得到了 。接下来就是反演了,其实反演是很简单的,既然知道了 的本身的子集是他自己 (), 的子集是 (),那就很简单的得出反演的递推式了:与运算与运算类比或运算可以得到类似结论异或运算最常考的异或运算。异或的卷积是基于如下原理:若我们令 中 数量的奇偶性为 与 的奇偶性,那么 与 的奇偶性异或 与 的奇偶性等于 与 的奇偶性。对于 的运算其实也很好得到。公式如下:( 表示 奇偶性为 , 表示 的奇偶性为 )结论:同或运算类比异或运算给出公式:( 表示 奇偶性为 , 表示 的奇偶性为 )例题【CF103329F】【XXII Opencup, Grand Prix of XiAn】The Struggle 给出一个椭圆 ,其中所有整点的坐标均在 之间。求 的值。 题解 这是一道比较不裸的题,出题人提供了详细的英文题解,具体请见 此链接。本页面最近更新:2023/5/25 17:17:02,更新历史发现错误?想一起完善? 在 GitHub 上编辑此页!本页面贡献者:Xeonacid, BinDir0, Enter-tainer, Ir1d, lxlonlyn, nocriz, nocrizwang, Tiphereth-A, TrisolarisHD, xyf007本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用Copyright © 2016 - 2024 OI Wiki Team Made with Material for MkDocs 最近更新:39ad03d2, 2024-03-

算法笔记|快速沃尔什变换 FWT(或卷积、与卷积、异或卷积) - 知乎

算法笔记|快速沃尔什变换 FWT(或卷积、与卷积、异或卷积) - 知乎切换模式写文章登录/注册算法笔记|快速沃尔什变换 FWT(或卷积、与卷积、异或卷积)牛客竞赛致力于为中小学生提供NOI/NOIP等比赛信息资讯作者:hydingsy链接:https://ac.nowcoder.com/discuss/175529来源:牛客网快速沃尔什变换用于解决多项式位运算卷积。其计算过程和 \text{FFT} 类似。概述首先我们回忆一下多项式卷积: C_k = \sum_{i + j = k} A_i\times B_j 在「算法笔记」快速傅里叶变换 FFT 中我们将多项式 A(x) 和B(x) 转化为点值表达,然后重新转化为系数表达。接下来考虑如下卷积形式:\begin{align*} C_k &= \sum_{i | j = k} A_i\times B_j \\ C_k &= \sum_{i \& j = k} A_i\times B_j \\ C_k &= \sum_{i \oplus j = k} A_i\times B_j \end{align*} 其中 |, \&, \oplus 分别表示按位或、按位与、按位异或。这样就没法使用 \text{FFT}​ 解决了,我们需要引进新的方法:快速沃尔什变换。下文会分类介绍这 3 类卷积的解决方法。其中定义部分是一种构造出来的变换方法,证明部分将使用数学归纳法证明一些引理或定理,代码部分为该卷积的实现。符号表示首先我们认为下文提及的多项式的长度均为 2 的非负整数次幂。为了方便表述,我们定义如下如下符号及其含义,下文不再赘述。\begin{array}{} A, B & \text{多项式,其长度为}\ n\text{,次数为}\ n - 1 \\ A_0, A_1 & \text{多项式}\ A\ \text{的前}\ \frac{n}{2}\ \text{位、后}\ \frac{n}{2}\ \text{位} \\ A + B & \text{将多项式}\ A, B\ \text{对应位加(减、乘),} \\ & \text{其系数表达式为}\ (A_0 + B_0, A_1 + B_1, \cdots, A_{n - 1} + B_{n - 1}) \\ A \oplus B & \text{将多项式}\ A, B\ \text{异或(与、或)卷积,} \\ & \text{其系数表达式为}\ (\sum_{i \oplus j = 0} A_i \times B_j, \sum_{i \oplus j = 1} A_i \times B_j, \cdots, \sum_{i \oplus j = n - 1} A_i \times B_j) \\ \text{FWT}(A) & \text{多项式}\ A\ \text{的 FWT 变换} \\ (A, B) & \text{将多项式}\ A, B\ \text{前后拼接起来} \end{array} 其中需要尤其注意:这里定义的多项式异或、与、或均为卷积形式!并不是对应系数位运算!或卷积定义\text{FWT}(A) = \begin{cases} (\text{FWT}(A_0), \text{FWT}(A_0 + A_1)) & n > 1 \\ A & n = 1 \end{cases} 证明1、两个多项式相加后的 \text{FWT} 变换等于分别 \text{FWT} 的和: \text{FWT}(A + B) = \text{FWT}(A) + \text{FWT}(B) 当 n = 1 时 \begin{align*} \text{FWT}(A + B) & = A + B \\ & = \text{FWT}(A) + \text{FWT}(B) \end{align*} 当 n > 1 时 \begin{align*} \text{FWT}(A + B) & = (\text{FWT}(A_0 + B_0), \text{FWT}(A_0 + A_1 + B_0 + B_1)) \\ & = (\text{FWT}(A_0) + \text{FWT}(B_0), \text{FWT}(A_0) + \text{FWT}(A_1) + \text{FWT}(B_0) + \text{FWT}(B_1)) \\ & = (\text{FWT}(A_0) , \text{FWT}(A_0) + \text{FWT}(A_1)) + (\text{FWT}(B_0), \text{FWT}(B_0) + \text{FWT}(B_1)) \\ & = \text{FWT}(A) + \text{FWT}(B) \end{align*} 2、两个多项式或卷积的 \text{FWT} 变换等于分别 \text{FWT} 的积: \text{FWT}(A | B) = \text{FWT}(A)\times FWT(B) 当 n = 1 时 \begin{align*} \text{FWT}(A | B) & = A \times B \\ & = \text{FWT}(A) \times \text{FWT}(B) \end{align*} 当 n > 1 时 \begin{align*} \text{FWT}(A | B) & = \text{FWT}((A | B)_0, (A | B)_1) \\ & = \text{FWT}(A_0 | B_0, A_0 | B_1 + A_1 | B_0 + A_1 | B_1) \\ & = (\text{FWT}(A_0 | B_0), \text{FWT}(A_0 | B_0 + A_0 | B_1 + A_1 | B_0 + A_1 | B_1)) \\ & = (\text{FWT}(A_0) \times \text{FWT}(B_0), \\ & \qquad \text{FWT}(A_0) \times \text{FWT}(B_0) + \text{FWT}(A_0) \times \text{FWT}(B_1) + \text{FWT}(A_1) \times \text{FWT}(B_0) + \text{FWT}(A_1) \times \text{FWT}(B_1)) \\ & = (\text{FWT}(A_0) \times \text{FWT}(B_0), (\text{FWT}(A_0) + \text{FWT}(A_1)) \times (\text{FWT}(B_0) + \text{FWT}(B_1))) \\ & = (\text{FWT}(A_0) \times \text{FWT}(B_0), \text{FWT}(A_0 + A_1) \times \text{FWT}(B_0 + B_1)) \\ & = (\text{FWT}(A_0), \text{FWT}(A_0 + A_1)) \times (\text{FWT}(B_0), \text{FWT}(B_0 + B_1)) \\ & = \text{FWT}(A)\times \text{FWT}(B) \end{align*}逆变换代码void FWTor(std::vector &a, bool rev) {

int n = a.size();

for (int l = 2, m = 1; l <= n; l <<= 1, m <<= 1) {

for (int j = 0; j < n; j += l) for (int i = 0; i < m; i++) {

if (!rev) add(a[i + j + m], a[i + j]);

else sub(a[i + j + m], a[i + j]);

}

}

}

与卷积定义\text{FWT}(A) = \begin{cases} (\text{FWT}(A_0 + A_1), \text{FWT}(A_1)) & n > 1 \\ A & n = 1 \end{cases} 证明1、两个多项式相加后的 \text{FWT} 变换等于分别 \text{FWT} 的和: \text{FWT}(A + B) = \text{FWT}(A) + \text{FWT}(B) 当 n=1 时 \begin{align*} \text{FWT}(A + B) & = A + B \\ & = \text{FWT}(A) + \text{FWT}(B) \end{align*} 当 n > 1 时 \begin{align*} \text{FWT}(A + B) & = (\text{FWT}(A_0 + A_1 + B_0 + B_1), \text{FWT}(A_1 + B_1)) \\ & = (\text{FWT}(A_0) + \text{FWT}(A_1) + \text{FWT}(B_0) + \text{FWT}(B_1), \text{FWT}(A_1) + \text{FWT}(B_1)) \\ & = (\text{FWT}(A_0) + \text{FWT}(A_1), \text{FWT}(A_1)) + (\text{FWT}(B_0) + \text{FWT}(B_1), \text{FWT}(B_1)) \\ & = \text{FWT}(A) + \text{FWT}(B) \end{align*} 2、两个多项式与卷积的 \text{FWT} 变换等于分别 \text{FWT} 的积: \text{FWT}(A \& B) = \text{FWT}(A)\times FWT(B) 当 n = 1 时 \begin{align*} \text{FWT}(A \& B) & = A \times B \\ & = \text{FWT}(A) \times \text{FWT}(B) \end{align*} 当 n > 1 时 \begin{align*} \text{FWT}(A \& B) & = \text{FWT}((A \& B)_0, (A \& B)_1) \\ & = \text{FWT}(A_0 \& B_0 + A_1 \& B_0 + A_0 \& B_1, A_1 \& B_1) \\ & = (\text{FWT}(A_0 \& B_0 + A_1 \& B_0 + A_0 \& B_1 + A_1 \& B_1), \text{FWT}(A_1 \& B_1)) \\ & = (\text{FWT}(A_0) \times \text{FWT}(B_0) + \text{FWT}(A_0) \times \text{FWT}(B_1) + \text{FWT}(A_1) \times \text{FWT}(B_0) + \text{FWT}(A_1) \times \text{FWT}(B_1), \\ & \qquad \text{FWT}(A_1) \times \text{FWT}(B_1)) \\ & = ((\text{FWT}(A_0) + \text{FWT}(A_1)) \times (\text{FWT}(B_0) + \text{FWT}(B_1)), \text{FWT}(A_1) \times \text{FWT}(B_1)) \\ & = (\text{FWT}(A_0 + A_1) \times \text{FWT}(B_0 + B_1), \text{FWT}(A_1) \times \text{FWT}(B_1)) \\ & = (\text{FWT}(A_0 + A_1), \text{FWT}(A_1)) \times (\text{FWT}(B_0 + B_1), \text{FWT}(B_1)) \\ & = \text{FWT}(A)\times \text{FWT}(B) \end{align*} 逆变换\text{FWT}(A) = (\text{FWT}(A_0) + \text{FWT}(A_1), \text{FWT}(A_1)) \\ \text{IFWT}(A) = (\text{IFWT}(A_0) - \text{IFWT}(A_1), \text{IFWT}(A_1)) 代码void FWTand(std::vector &a, bool rev) {

int n = a.size();

for (int l = 2, m = 1; l <= n; l <<= 1, m <<= 1) {

for (int j = 0; j < n; j += l) for (int i = 0; i < m; i++) {

if (!rev) add(a[i + j], a[i + j + m]);

else sub(a[i + j], a[i + j + m]);

}

}

}

异或卷积定义\text{FWT}(A) = \begin{cases} (\text{FWT}(A_0 + A_1), \text{FWT}(A_0 -A_1)) & n > 1 \\ A & n = 1 \end{cases} 证明1、两个多项式相加后的 \text{FWT} 变换等于分别 \text{FWT} 的和: \text{FWT}(A + B) = \text{FWT}(A) + \text{FWT}(B) 当 n = 1 时 \begin{align*} \text{FWT}(A + B) & = A + B \\ & = \text{FWT}(A) + \text{FWT}(B) \end{align*} 当 n > 1 时 \begin{align*} \text{FWT}(A + B) & = (\text{FWT}(A_0 + A_1 + B_0 + B_1), \text{FWT}(A_0 - A_1 + B_0 - B_1)) \\ & = (\text{FWT}(A_0) + \text{FWT}(A_1) + \text{FWT}(B_0) + \text{FWT}(B_1), \text{FWT}(A_0) - \text{FWT}(A_1) + \text{FWT}(B_0) - \text{FWT}(B_1)) \\ & = (\text{FWT}(A_0) + \text{FWT}(A_1), \text{FWT}(A_0) - \text{FWT}(A_1)) + (\text{FWT}(B_0) + \text{FWT}(B_1), \text{FWT}(B_0) - \text{FWT}(B_1)) \\ & = \text{FWT}(A) + \text{FWT}(B) \end{align*} 2、两个多项式异或卷积的 \text{FWT}​ 变换等于分别 \text{FWT}​ 的积: \text{FWT}(A \oplus B) = \text{FWT}(A)\times FWT(B) 当 n = 1 时 \begin{align*} \text{FWT}(A \oplus B) & = A \times B \\ & = \text{FWT}(A) \times \text{FWT}(B) \end{align*} 当 n > 1 时 \begin{align*} \text{FWT}(A \oplus B) & = \text{FWT}((A \oplus B)_0, (A \oplus B)_1) \\ & = \text{FWT}(A_0 \oplus B_0 + A_1 \oplus B_1, A_0 \oplus B_1 + A_1 \oplus B_0) \\ & = (\text{FWT}(A_0 \oplus B_0 + A_1 \oplus B_1 + A_0 \oplus B_1 + A_1 \oplus B_0), \text{FWT}(A_0 \oplus B_0 + A_1 \oplus B_1 - A_0 \oplus B_1 - A_1 \oplus B_0)) \\ & = (\text{FWT}(A_0) \times \text{FWT}(B_0) + \text{FWT}(A_1) \times \text{FWT}(B_1) + \text{FWT}(A_0) \times \text{FWT}(B_1) + \text{FWT}(A_1) \times \text{FWT}(B_0), \\ & \qquad \text{FWT}(A_0) \times \text{FWT}(B_0) + \text{FWT}(A_1) \times \text{FWT}(B_1) - \text{FWT}(A_0) \times \text{FWT}(B_1) - \text{FWT}(A_1) \times \text{FWT}(B_0)) \\ & = ((\text{FWT}(A_0) + \text{FWT}(A_1)) \times (\text{FWT}(B_0) + \text{FWT}(B_1)), (\text{FWT}(A_0) - \text{FWT}(A_1)) \times (\text{FWT}(B_0) - \text{FWT}(B_1))) \\ & = (\text{FWT}(A_0 + A_1) \times \text{FWT}(B_0 + B_1), \text{FWT}(A_0 - A_1) \times \text{FWT}(B_0 - B_1)) \\ & = (\text{FWT}(A_0 + A_1), \text{FWT}(A_0 - A_1)) \times (\text{FWT}(B_0 + B_1), \text{FWT}(B_0 - B_1)) \\ & = \text{FWT}(A)\times \text{FWT}(B) \end{align*} 逆变换\text{FWT}(A) = (\text{FWT}(A_0) + \text{FWT}(A_1), \text{FWT}(A_0) - \text{FWT}(A_1)) \\ \text{IFWT}(A) = \left(\frac{\text{IFWT}(A_0) + \text{IFWT}(A_1)}{2}, \frac{\text{IFWT}(A_0) - \text{IFWT}(A_1)}{2}\right) 代码void FWTxor(std::vector &a, bool rev) {

int n = a.size(), inv2 = (P + 1) >> 1;

for (int l = 2, m = 1; l <= n; l <<= 1, m <<= 1) {

for (int j = 0; j < n; j += l) for (int i = 0; i < m; i++) {

int x = a[i + j], y = a[i + j + m];

if (!rev) {

a[i + j] = (x + y) % P;

a[i + j + m] = (x - y + P) % P;

} else {

a[i + j] = 1LL * (x + y) * inv2 % P;

a[i + j + m] = 1LL * (x - y + P) * inv2 % P;

}

}

}

}

完整代码#include

#include

#include

const int P = 998244353;

void add(int &x, int y) {

(x += y) >= P && (x -= P);

}

void sub(int &x, int y) {

(x -= y) < 0 && (x += P);

}

struct FWT {

int extend(int n) {

int N = 1;

for (; N < n; N <<= 1);

return N;

}

void FWTor(std::vector &a, bool rev) {

int n = a.size();

for (int l = 2, m = 1; l <= n; l <<= 1, m <<= 1) {

for (int j = 0; j < n; j += l) for (int i = 0; i < m; i++) {

if (!rev) add(a[i + j + m], a[i + j]);

else sub(a[i + j + m], a[i + j]);

}

}

}

void FWTand(std::vector &a, bool rev) {

int n = a.size();

for (int l = 2, m = 1; l <= n; l <<= 1, m <<= 1) {

for (int j = 0; j < n; j += l) for (int i = 0; i < m; i++) {

if (!rev) add(a[i + j], a[i + j + m]);

else sub(a[i + j], a[i + j + m]);

}

}

}

void FWTxor(std::vector &a, bool rev) {

int n = a.size(), inv2 = (P + 1) >> 1;

for (int l = 2, m = 1; l <= n; l <<= 1, m <<= 1) {

for (int j = 0; j < n; j += l) for (int i = 0; i < m; i++) {

int x = a[i + j], y = a[i + j + m];

if (!rev) {

a[i + j] = (x + y) % P;

a[i + j + m] = (x - y + P) % P;

} else {

a[i + j] = 1LL * (x + y) * inv2 % P;

a[i + j + m] = 1LL * (x - y + P) * inv2 % P;

}

}

}

}

std::vector Or(std::vector a1, std::vector a2) {

int n = std::max(a1.size(), a2.size()), N = extend(n);

a1.resize(N), FWTor(a1, false);

a2.resize(N), FWTor(a2, false);

std::vector A(N);

for (int i = 0; i < N; i++) A[i] = 1LL * a1[i] * a2[i] % P;

FWTor(A, true);

return A;

}

std::vector And(std::vector a1, std::vector a2) {

int n = std::max(a1.size(), a2.size()), N = extend(n);

a1.resize(N), FWTand(a1, false);

a2.resize(N), FWTand(a2, false);

std::vector A(N);

for (int i = 0; i < N; i++) A[i] = 1LL * a1[i] * a2[i] % P;

FWTand(A, true);

return A;

}

std::vector Xor(std::vector a1, std::vector a2) {

int n = std::max(a1.size(), a2.size()), N = extend(n);

a1.resize(N), FWTxor(a1, false);

a2.resize(N), FWTxor(a2, false);

std::vector A(N);

for (int i = 0; i < N; i++) A[i] = 1LL * a1[i] * a2[i] % P;

FWTxor(A, true);

return A;

}

} fwt;

int main() {

int n;

scanf("%d", &n);

std::vector a1(n), a2(n);

for (int i = 0; i < n; i++) scanf("%d", &a1[i]);

for (int i = 0; i < n; i++) scanf("%d", &a2[i]);

std::vector A;

A = fwt.Or(a1, a2);

for (int i = 0; i < n; i++) {

printf("%d%c", A[i], " \n"[i == n - 1]);

}

A = fwt.And(a1, a2);

for (int i = 0; i < n; i++) {

printf("%d%c", A[i], " \n"[i == n - 1]);

}

A = fwt.Xor(a1, a2);

for (int i = 0; i < n; i++) {

printf("%d%c", A[i], " \n"[i == n - 1]);

}

return 0;

}

习题「Luogu 4717」【模板】快速沃尔什变换「BZOJ 4589」Hard Nim「hihoCoder 1230」The Celebration of Rabbits「HDU 5909」Tree Cutting与作者交流:https://ac.nowcoder.com/discuss/175529更多算法和题解:https://ac.nowcoder.com/acm/contest/discuss发布于 2019-05-16 16:26算法卷积​赞同 27​​添加评论​分享​喜欢​收藏​申请

学习:多项式算法----FWT - 七月流 - 博客园

学习:多项式算法----FWT - 七月流 - 博客园

会员

周边

新闻

博问

AI培训

云市场

所有博客

当前博客

我的博客

我的园子

账号设置

简洁模式 ...

退出登录

注册

登录

七月流的小博客

为算法而生

首页

新随笔

联系

管理

学习:多项式算法----FWT

FWT也称快速沃尔什变换,是用来求多项式之间位运算的系数的。FWT的思想与FFT有异曲同工之妙,但较FFT来说,FWT比较简单。

 

前言

 

之前学习FFT(快速傅里叶变换)的时候,我们知道FFT是用来快速求两个多项式乘积的,即求序列C:

$$C_k=\sum_{i+j=k}A_iB_j$$

 

而FWT解决的多项式的位运算,即知道两个序列A与B,求:

$$C_k=\sum_{i\&j=k}A_iB_j\;\;(\& 表示位运算"与")$$

$$C_k=\sum_{i|j=k}A_iB_j\;\;(| 表示位运算"或")$$

$$C_k=\sum_{i\land j=k}A_iB_j\;\;(\land 表示位运算"异或")$$

 

如图FFT的解决方法,在FWT中,我们需要找到一种线性变换$FWT$,使得原序列$A$变成一个新的序列$FWT(A)$,新序列与由原序列线性相关。

 

注意,由于FWT变换是一种线性变换,所以一定满足

$$FWT(A)+FWT(B)=FWT(A+B)$$

 

与FFT一样,我么需要把序列用0补成2的幂次方个,然后分割成序列为2的区间,然后更新数值,再合并,再一段段更新,再合并....直到最后合并成一个序列,然后进行最后一次更新即可得到变换后的序列。

 

 

 

FWT_OR

 

已知两个序列A,B,求新的序列C,其中

$$C=\left\{\sum_{i|j=0}A_iB_j,\sum_{i|j=1}A_iB_j,\sum_{i|j=2}A_iB_j,...\right\}$$

$$C_k=\sum_{i|j=k}A_iB_j$$

 

假设序列为$A$,前一半元素(前$2^{n-1}$个)元素组成的序列为$A_0$,后一半元素(后$2^{n-1}$个)元素组成的序列为$A_1$,故$A=(A_0,A_1)$

 

若序列A的长度为$2^n$,更新方法:

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

","表示合并前后两个序列。

 

此时可以证明$$FWT(C)=FWT(A|B)=FWT(A)*FWT(B)$$

借某位大佬的证明方法:

$FWT(A|B)=FWT((A|B)_0,(A|B)_1)$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =FWT(A_0|B_0,A0|B_1+A_1|B0+A_1|B_1)$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =(FWT(A_0|B_0),FWT(A_0|B_0+A_0|B_1+A_1|B_0+A_1|B_1))$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =(FWT(A_0)×FWT(B_0),$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FWT(A_0)×FWT(B_0)+FWT(A_0)×FWT(B_1)+$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FWT(A_1)×FWT(B_0)+FWT(A_1)×FWT(B_1))$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =(FWT(A_0)×FWT(B_0),(FWT(A_0)+FWT(A_1))×$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (FWT(B_0)+FWT(B_1)))$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =(FWT(A_0),FWT(A_0+A_1))×(FWT(B_0),FWT(B_0+B_1))$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =FWT(A)×FWT(B)$

 

然后对FWT(C)序列进行FWT逆变换(UFWT)即可得到C序列。

 

逆变换的更新方法可以根据正变换的形式得到,为

$$UFWT(A)=(UFWT(A_0),UFWT(A_1)-UFWT(A_0))$$

 

FWT或变换代码:

typedef long long ll;

void FWT_or(ll *a,int n){

for(int i=2;i<=n;i<<=1)//i表示分治的区间

for(int p=i>>1,j=0;j

for(int k=j;k

a[k+p]+=a[k];//更新

return;

}

 

UFWT或变换代码:

typedef long long ll;

void UFWT_or(ll *a,int n){

for(int i=2;i<=n;i<<=1)

for(int p=i>>1,j=0;j

for(int k=j;k

a[k+p]-=a[k];

return;

}

 

合并代码:

void FWT_or(ll *a,int n,int opt){

for(int i=2;i<=n;i<<=1)

for(int p=i>>1,j=0;j

for(int k=j;k

a[k+p]+=a[k]*opt;

return;

}

U/FWT_or

 

 

 

 

FWT_AND

 

已知两个序列A,B,求新的序列C,其中

$$C=\left\{\sum_{i\&j=0}A_iB_j,\sum_{i\&j=1}A_iB_j,\sum_{i\&j=2}A_iB_j,...\right\}$$

$$C_k=\sum_{i\&j=k}A_iB_j$$

 

假设序列为$A$,前一半元素(前$2^{n-1}$个)元素组成的序列为$A_0$,后一半元素(后$2^{n-1}$个)元素组成的序列为$A_1$,故$A=(A_0,A_1)$

 

若序列A的长度为$2^n$,更新方法:

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

","表示合并前后两个序列。

 

此时也可以证明$$FWT(C)=FWT(A\&B)=FWT(A)*FWT(B)$$

证明方法:

$FWT(A\&B)=FWT((A\&B)_0,(A\&B)_1)$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =FWT(A_0\&B_0+A_0\&B_1+A_1\&B_0,A_1\&B_1)$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =(FWT(A_0\&B_0+A_0\&B_1+A_1\&B_0+A_1\&B_1),FWT(A_1\&B_1))$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =((FWT(A0)+FWT(A1))×(FWT(B0)+FWT(B1)),FWT(A1)∗FWT(B1))$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =(FWT(A0+A1),FWT(A1))×(FWT(B0+B1),FWT(B1))$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =FWT(A)×FWT(B)$

 

然后对FWT(C)序列进行FWT逆变换(UFWT)即可得到C序列。

 

逆变换的更新方法可以根据正变换的形式得到,为

$$UFWT(A)=(UFWT(A_0)-UFWT(A_1),UFWT(A_1))$$

 

FWT与变换代码:

void FWT_and(ll *a,int n){

for(int i=2;i<=n;i<<=1)

for(int p=i>>1,j=0;j

for(int k=j;k

a[k]+=a[k+p];

return;

}

 

UFWT或变换代码:

void UFWT_and(ll *a,int n){

for(int i=2;i<=n;i<<=1)

for(int p=i>>1,j=0;j

for(int k=j;k

a[k]-=a[k+p];

return;

}

 

合并代码:

void FWT_and(ll *a,int n,int opt){

for(int i=2;i<=n;i<<=1)

for(int p=i>>1,j=0;j

for(int k=j;k

a[k]+=a[k+p]*opt;

return;

}

U/FWT_and

 

 

 

 

FWT_XOR

 

已知两个序列A,B,求新的序列C,其中

$$C=\left\{\sum_{i\oplus j=0}A_iB_j,\sum_{i\oplus j=1}A_iB_j,\sum_{i\oplus j=2}A_iB_j,...\right\}$$

$$C_k=\sum_{i\oplus j=k}A_iB_j$$

 

假设序列为$A$,前一半元素(前$2^{n-1}$个)元素组成的序列为$A_0$,后一半元素(后$2^{n-1}$个)元素组成的序列为$A_1$,故$A=(A_0,A_1)$

 

若序列A的长度为$2^n$,更新方法:

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

","表示合并前后两个序列。

 

此时仍然可以证明$$FWT(C)=FWT(A\oplus B)=FWT(A)*FWT(B)$$

证明方法:

$FWT(A⊕B)=(FWT(A⊕B)_0+FWT(A⊕B)_1,FWT(A⊕B)_0−FWT(A⊕B)_1)$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =(FWT(A_0⊕B_0+A_1⊕B_1+A_1⊕B_0+A_0⊕B_1),$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FWT(A_0⊕B_0+A_1⊕B_1−A_1⊕B_0−A_0⊕B_1))$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =((FWT(A_0)+FWT(A_1))×(FWT(B_0)+FWT(B_1)),$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (FWT(A_0)−FWT(A_1))×(FWT(B_0)−FWT(B_1))$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =(FWT(A_0+A_1)×(B_0+B_1),FWT(A_0−A_1)×FWT(B_0−B_1))$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =(FWT(A_0+A_1),FWT(A_0−A_1))×(FWT(B_0+B_1),FWT(B_0−B_1))$

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =FWT(A)×FWT(B)$

 

然后对FWT(C)序列进行FWT逆变换(UFWT)即可得到C序列。

 

逆变换的更新方法可以根据正变换的形式得到,为

$$UFWT(A)=(\frac {UFWT(A_0)+UFWT(A_1)}2,\frac {UFWT(A_0)-UFWT(A_1)}2)$$

 

FWT异或变换代码:

void FWT_xor(ll *a,int n){

for(int i=2;i<=n;i<<=1)

for(int p=i>>1,j=0;j

for(int k=j;k

ll x=a[k],y=a[k+p];

a[k]=x+y;a[k+p]=x-y;

}

return 0;

}

 

UFWT变换代码:

void UFWT_xor(ll *a,int n){

for(int i=2;i<=n;i<<=1)

for(int p=i>>1,j=0;j

for(int k=j;k

ll x=a[k],y=a[k+p];

a[k]=(x+y)/2,a[k+p]=(x-y)/2;

}

return 0;

}

 

合并代码:

void FWT_xor(ll *a,int n,int opt){

for(int i=2;i<=n;i<<=1)

for(int p=i>>1,j=0;j

for(int k=j;k

ll x=a[k],y=a[k+p];

if(opt==1) a[k]=x+y;a[k+p]=x-y;

else a[k]=(x+y)/2,a[k+p]=(x-y)/2;

}

return 0;

}

U/FWT_xor

 

 

 

FWT异或变换的特殊作用

 

在FWT异或变换中,我们主要解决一个问题

$$h(i)=\sum_{j\oplus k=i}f(j)g(k)$$

 

根据某站某大佬的讲解,假设存在三个集合$L,R,S$满足

$$h(S)=\sum_{R\oplus L=i}f(R)g(L)$$

 

则为了解决快速多项式异或,我们需要将上面的式子变形。

首先介绍一个等式,假设全集为U,集合内有n个元素,其中$|T|$表示集合T的大小,则

$$\frac 1{2^n}\sum_{T\subseteq U}(-1)^{|W\cap T|}=1$$

上面的式子仅在$W=\varnothing$时成立

 

解释一下:由于集合$T$是集合$U$的子集,故集合$T$有$2^n$中可能,一旦$W$不是空集,$(-1)^{|W\cap T|}$就可能等于1,那么$\sum_{T\subseteq U}(-1)^{|W\cap T|}$就会小于$2^n$。所以只有当$W$是空集时,上面式子才等于1

 

有了上面的等式,就可以变形了,由于$R\oplus L=S$,故$R\oplus L\oplus S=\varnothing$

$$h(S)=\sum_{R\oplus L=i}f(R)g(L)$$

$$=\sum_{R\subseteq U}\sum_{L\subseteq U}[R\oplus L\oplus S=\varnothing]f(L)g(R)$$

$$=\sum_{R\subseteq U}\sum_{L\subseteq U}\frac 1{2^n}\sum_{T\subseteq U}(-1)^{|R\oplus L\oplus S\cap T|}f(L)g(R)$$

 

下面证明$|T\cap \oplus^{n}_{i=1}S_i|$与$\sum_{i=1}^n|S_i\cap T|$的奇偶性相同,先证明n=2的情况:

假设$|T\cap S_1|=A,|T\cap S_2|=B$

1.假设$T\cap S_1$与$T\cap S_2$没有相同位的数相同,那么:

$$(-1)^{\sum_{i=1}^2|S_i\cap T|}=(-1)^{|S_1\cap T|+|S_2\cap T|}=(-1)^{A+B}=(-1)^{|T\cap (S_1\oplus S_2)|}$$

2.假设$T\cap S_1$与$T\cap S_2$有x组相同位的数相同,那么:

$$(-1)^{\sum_{i=1}^2|S_i\cap T|}=(-1)^{|S_1\cap T|+|S_2\cap T|}=(-1)^{A+B}$$$$(-1)^{|T\cap (\oplus_{i=1}^2S_i)|}=(-1)^{|T\cap (S_1\oplus S_2)|}=(-1)^{A+B-2x}=(-1)^{A+B}$$

当然n等于任何数的时候也是像上面一样可以证明的,所以$$(-1)^{|R\oplus L\oplus S\cap T|}=(-1)^{|R\cap T|+|S\cap T|+|L\cap T|}$$

 

故上面式子继续变形可得

$$\frac 1{2^n}\sum_{L\subseteq U}\sum_{R\subseteq U}\sum_{T\subseteq U}(-1)^{|L\cap T|}(-1)^{|R\cap T|}(-1)^{|S\cap T|}f(R)g(L)$$

 

于是发现了FWT_xor变形的本质,即变形后的序列$f(T)$与变形前序列$f(R)$的关系

$$f(T)=\sum_{R\subseteq U}(-1)^{|R\cap T|}f(R)$$

 

通过以上的探究,得到结论:假设原序列为A,变形后的序列为A',那么

$$A'[x]=\sum_{|x\&i|\bmod {2}=0}A[i]-\sum_{|x\&i|\bmod {2}\neq 0}A[i]$$

 

 

 

 

例题

 1.2019牛客暑期多校训练营(第一场)----D-Parity of Tuples:https://blog.csdn.net/weixin_43702895/article/details/97114770

 

 

 

 

 

 

 

posted @

2019-10-03 20:06 

七月流 

阅读(2119) 

评论(0) 

编辑 

收藏 

举报

会员力量,点亮园子希望

刷新页面返回顶部

公告

Copyright © 2024 七月流

Powered by .NET 8.0 on Kubernetes

快速沃尔什变换(FWT)详详详解-CSDN博客

>

快速沃尔什变换(FWT)详详详解-CSDN博客

快速沃尔什变换(FWT)详详详解

最新推荐文章于 2024-01-21 21:18:35 发布

Hypoc_

最新推荐文章于 2024-01-21 21:18:35 发布

阅读量4.5k

收藏

28

点赞数

15

分类专栏:

# 多项式

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/a_forever_dream/article/details/105110089

版权

多项式

专栏收录该内容

19 篇文章

2 订阅

订阅专栏

文章目录

介绍思路或卷积正变换证明

求解证明感性理解理性证明

逆变换感性理解理性证明

与卷积正变换证明

求解证明逆变换

异或卷积正变换证明

求解证明逆变换

模板题

介绍

我们以前常见的多项式乘法长这个亚子:

C

[

k

]

=

i

+

j

=

k

A

[

i

]

×

B

[

j

]

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

C[k]=i+j=k∑​A[i]×B[j]

F

W

T

FWT

FWT 用来处理的,与

F

F

T

FFT

FFT 稍稍不同,是这样的卷积:

C

[

k

]

=

i

j

=

k

A

[

i

]

×

B

[

j

]

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

C[k]=i⊕j=k∑​A[i]×B[j]

其中,

\oplus

⊕ 可以是

&

,

,

Λ

\&,|,\Lambda

&,∣,Λ,这三种符号分别对应

a

n

d

,

o

r

,

x

o

r

and,or,xor

and,or,xor。

为了方便,首先做一些约定(下面

A

,

B

A,B

A,B 代表多项式):

A

+

B

=

(

A

[

0

]

+

B

[

0

]

,

A

[

1

]

+

B

[

1

]

,

)

A+B=(A[0]+B[0],A[1]+B[1],\cdots)

A+B=(A[0]+B[0],A[1]+B[1],⋯),即按位相加

A

B

=

(

A

[

0

]

B

[

0

]

,

A

[

1

]

B

[

1

]

,

)

A-B=(A[0]-B[0],A[1]-B[1],\cdots)

A−B=(A[0]−B[0],A[1]−B[1],⋯),即按位相减

A

B

=

(

A

[

0

]

×

B

[

0

]

,

A

[

1

]

×

B

[

1

]

,

)

A*B=(A[0]\times B[0],A[1]\times B[1],\cdots)

A∗B=(A[0]×B[0],A[1]×B[1],⋯),即按位相乘(这个要注意,别和卷积搞混了)

A

B

=

(

i

j

=

0

A

[

i

]

×

B

[

j

]

 

,

i

j

=

1

A

[

i

]

×

B

[

j

]

 

,

)

A\oplus B=(\sum\limits_{i\oplus j=0}A[i]\times B[j]~,\sum\limits_{i\oplus j=1}A[i]\times B[j]~,\cdots)

A⊕B=(i⊕j=0∑​A[i]×B[j] ,i⊕j=1∑​A[i]×B[j] ,⋯),本质就是上面的那个卷积

思路

大致思路与

F

F

T

FFT

FFT 一致,将要卷在一起的两个多项式先正变换,然后按位相乘,最后逆变换回来即可。

或卷积

卷积的公式是这样的:

C

[

k

]

=

i

j

=

k

A

[

i

]

×

B

[

j

]

C[k]=\sum\limits_{i|j=k}A[i]\times B[j]

C[k]=i∣j=k∑​A[i]×B[j]。可以表示为

C

=

A

B

C=A|B

C=A∣B。

其实或卷积和与卷积的本质应该是

F

M

T

FMT

FMT,但是大部分人将它们归在

F

W

T

FWT

FWT 门下了,所以也放在这里讲。

正变换

定义:

F

W

T

(

A

)

[

i

]

=

j

i

A

[

j

]

FWT(A)[i]=\sum_{j|i} A[j]

FWT(A)[i]=∑j∣i​A[j]。这个是正变换后得到的数组的意义,简单来说,就是下标的子集对应的位置之和,其中

j

i

j|i

j∣i 表示

j

j

j 是

i

i

i 的子集。

那么有一个很显然的性质:

F

W

T

(

A

)

+

F

W

T

(

B

)

=

F

W

T

(

A

+

B

)

FWT(A)+FWT(B)=FWT(A+B)

FWT(A)+FWT(B)=FWT(A+B)

证明: 我们拿每一位单独看:

F

W

T

(

A

)

[

i

]

=

j

i

A

[

j

]

FWT(A)[i]=\sum_{j|i}A[j]

FWT(A)[i]=∑j∣i​A[j]

F

W

T

(

B

)

[

i

]

=

j

i

B

[

j

]

FWT(B)[i]=\sum_{j|i}B[j]

FWT(B)[i]=∑j∣i​B[j]

F

W

T

(

A

+

B

)

[

i

]

=

j

i

(

A

+

B

)

[

j

]

=

j

i

A

[

j

]

+

B

[

j

]

FWT(A+B)[i]=\sum_{j|i}(A+B)[j]=\sum_{j|i}A[j]+B[j]

FWT(A+B)[i]=∑j∣i​(A+B)[j]=∑j∣i​A[j]+B[j]

嗯……很显然可以得到

F

W

T

(

A

)

[

i

]

+

F

W

T

(

B

)

[

i

]

=

F

W

T

(

A

+

B

)

[

i

]

FWT(A)[i]+FWT(B)[i]=FWT(A+B)[i]

FWT(A)[i]+FWT(B)[i]=FWT(A+B)[i]。

再定义一个东西:设

A

A

A 这个多项式有

2

n

2^n

2n 项,那么

A

0

A_0

A0​ 表示前

2

n

1

2^{n-1}

2n−1 项,

A

1

A_1

A1​ 表示后

2

n

1

2^{n-1}

2n−1 项。

那么其实很容易得到递归的公式:

F

W

T

(

A

)

=

{

(

F

W

T

(

A

0

)

,

F

W

T

(

A

0

)

+

F

W

T

(

A

1

)

)

(

n

>

0

)

A

(

n

=

0

)

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

FWT(A)={(FWT(A0​),FWT(A0​)+FWT(A1​))A​(n>0)(n=0)​

你问我

(

A

,

B

)

(A,B)

(A,B) 这样的表示是什么意思?别忘了

A

,

B

A,B

A,B 是多项式,你可以认为这是将两个多项式拼接在了一起。就像

A

=

(

A

0

,

A

1

)

A=(A_0,A_1)

A=(A0​,A1​)。

证明

n

=

0

n=0

n=0 时很显然,就不讲了。

仔细观察,

A

0

A_0

A0​ 与

A

1

A_1

A1​ 的区别在于,

A

0

A_0

A0​ 部分下标最高位是

0

0

0,而

A

1

A_1

A1​ 的最高位是

1

1

1,也就是说,

A

0

A_0

A0​ 在对应位置上是

A

1

A_1

A1​ 的子集,因为只有最高位不一样,其他位都一样,所以我们将

A

0

A_0

A0​ 加给

A

1

A_1

A1​。

又因为

A

1

A_1

A1​ 中不可能有任何一位是

A

0

A_0

A0​ 的任意一个位置的子集,所以左半部分就只是

F

W

T

(

A

0

)

FWT(A_0)

FWT(A0​)。

这样递归下去,依次处理完第

n

1

n-1

n−1 位,第

n

2

n-2

n−2 位,……,第

1

1

1 位后,就求出了

F

W

T

(

A

)

FWT(A)

FWT(A)。

求解证明

求出

F

W

T

(

A

)

FWT(A)

FWT(A) 和

F

W

T

(

B

)

FWT(B)

FWT(B) 之后,对应位置相乘就得到了

F

W

T

(

C

)

FWT(C)

FWT(C),然后逆变换就可以得到多项式

C

C

C。

这里就需要证明,为什么

F

W

T

(

C

)

=

F

W

T

(

A

B

)

=

F

W

T

(

A

)

F

W

T

(

B

)

FWT(C)=FWT(A|B)=FWT(A)*FWT(B)

FWT(C)=FWT(A∣B)=FWT(A)∗FWT(B)。

感性理解

感性理解其实很简单,

F

W

T

(

A

)

[

i

]

FWT(A)[i]

FWT(A)[i] 记录的是

i

i

i 的子集之和,

F

W

T

(

B

)

[

i

]

FWT(B)[i]

FWT(B)[i] 也是,那么他们相乘,其实就是双方子集中的每一个元素两两相乘,取出来的两个元素的下标或起来一定还是

i

i

i 的子集中的一个,由于

C

[

i

]

C[i]

C[i] 记录的是下标或起来为

i

i

i 的乘积之和,那么全部乘完之后,我们不仅得到了

C

[

i

]

C[i]

C[i],还得到了

i

i

i 的所有子集的

C

C

C,也就是

F

W

T

(

C

)

[

i

]

FWT(C)[i]

FWT(C)[i]。

理性证明

这玩意丑的很……相信没人想看的qwq,不过为了严谨,还是有必要写的啦。

下面为了区分属于…的子集和或运算两个意思,就不都用

|

∣ 了,属于…的子集用

\in

∈ 代替(只是在这个证明中)。

F

W

T

(

C

)

[

i

]

=

j

i

C

[

j

]

=

j

i

x

y

=

j

A

[

x

]

×

B

[

y

]

=

(

x

y

)

i

A

[

x

]

×

B

[

y

]

=

x

i

A

[

x

]

×

y

i

B

[

y

]

=

F

W

T

(

A

)

[

i

]

×

F

W

T

(

B

)

[

i

]

\begin{aligned} FWT(C)[i]&=\sum_{j\in i}C[j]\\ &=\sum_{j\in i}\sum_{x|y=j}A[x]\times B[y]\\ &=\sum_{(x|y)\in i}A[x]\times B[y]\\ &=\sum_{x\in i}A[x]\times\sum_{y\in i}B[y]\\ &=FWT(A)[i]\times FWT(B)[i] \end{aligned}

FWT(C)[i]​=j∈i∑​C[j]=j∈i∑​x∣y=j∑​A[x]×B[y]=(x∣y)∈i∑​A[x]×B[y]=x∈i∑​A[x]×y∈i∑​B[y]=FWT(A)[i]×FWT(B)[i]​

逆变换

逆变换我们称为

I

F

W

T

IFWT

IFWT,即满足

A

=

I

F

W

T

(

F

W

T

(

A

)

)

A=IFWT(FWT(A))

A=IFWT(FWT(A))。

这个其实只需要将上面的加号变成减号即可。

感性理解

可以类比前缀和来理解:

//知道每个位置的值求前缀和

for(int i=1;i<=n;i++)a[i]+=a[i-1];

//知道前缀和求每个位置的值

for(int i=n;i>=1;i--)a[i]-=a[i-1];

理性证明

其实证明也很简单,以及与卷积和异或卷积的理性证明其实都差不多。

证明: 我们现在已知

F

W

T

(

A

)

0

,

F

W

T

(

A

)

1

FWT(A)_0,FWT(A)_1

FWT(A)0​,FWT(A)1​,要求

A

0

,

A

1

A_0,A_1

A0​,A1​。

F

W

T

(

A

)

0

=

F

W

T

(

A

0

)

\because FWT(A)_0=FWT(A_0)

∵FWT(A)0​=FWT(A0​)

A

0

=

I

F

W

T

(

F

W

T

(

A

0

)

)

=

I

F

W

T

(

F

W

T

(

A

)

0

)

\therefore A_0=IFWT(FWT(A_0))=IFWT(FWT(A)_0)

∴A0​=IFWT(FWT(A0​))=IFWT(FWT(A)0​)

F

W

T

(

A

)

1

=

F

W

T

(

A

0

)

+

F

W

T

(

A

1

)

\because FWT(A)_1=FWT(A_0)+FWT(A_1)

∵FWT(A)1​=FWT(A0​)+FWT(A1​),即

F

W

T

(

A

1

)

=

F

W

T

(

A

)

1

F

W

T

(

A

)

0

FWT(A_1)=FWT(A)_1-FWT(A)_0

FWT(A1​)=FWT(A)1​−FWT(A)0​

A

1

=

I

F

W

T

(

F

W

T

(

A

1

)

)

=

I

F

W

T

(

F

W

T

(

A

)

1

F

W

T

(

A

)

0

)

\therefore A_1=IFWT(FWT(A_1))=IFWT(FWT(A)_1-FWT(A)_0)

∴A1​=IFWT(FWT(A1​))=IFWT(FWT(A)1​−FWT(A)0​)

代码实现(其实和

F

F

T

FFT

FFT 很像):

void FWT_or(ll *f,int type)//type为1是正变换,-1是逆变换

{

for(int mid=1;mid

for(int block=mid<<1,j=0;j

for(int i=j;i

f[i+mid]=(f[i+mid]+f[i]*type+mod)%mod;

}

与卷积

卷积的公式是这样的:

C

[

k

]

=

i

&

j

=

k

A

[

i

]

×

B

[

j

]

C[k]=\sum\limits_{i\&j=k}A[i]\times B[j]

C[k]=i&j=k∑​A[i]×B[j]。

正变换

定义:

F

W

T

(

A

)

[

i

]

=

i

j

A

[

j

]

FWT(A)[i]=\sum_{i|j}A[j]

FWT(A)[i]=∑i∣j​A[j],意思就是,

F

W

T

(

A

)

[

i

]

FWT(A)[i]

FWT(A)[i] 记录的是所有

A

[

j

]

A[j]

A[j] 的和,其中

i

,

j

i,j

i,j 满足

i

i

i 是

j

j

j 的子集。

这个显然也满足

F

W

T

(

A

)

+

F

W

T

(

B

)

=

F

W

T

(

A

+

B

)

FWT(A)+FWT(B)=FWT(A+B)

FWT(A)+FWT(B)=FWT(A+B)。

其实与卷积和或卷积十分相似,一个是前面的对后面的产生贡献,一个是后面的对前面产生贡献。

类比或卷积,可以得到与卷积的递归公式:

F

W

T

(

A

)

=

{

(

F

W

T

(

A

0

)

+

F

W

T

(

A

1

)

,

F

W

T

(

A

1

)

)

(

n

>

0

)

A

(

n

=

0

)

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

FWT(A)={(FWT(A0​)+FWT(A1​),FWT(A1​))A​(n>0)(n=0)​

证明

这就不用证了吧……和或卷积基本上一毛一样,就是

A

0

A_0

A0​ 和

A

1

A_1

A1​ 对应位置就差一个

1

1

1,所以

A

0

A_0

A0​ 是

A

1

A_1

A1​ 子集,所以把

A

1

A_1

A1​ 的贡献累加到

A

0

A_0

A0​ 上。

求解证明

如果理解了或运算的求解证明,那么与运算的其实也搞定了。

这里就直接贴一个数学证明了:

F

W

T

(

C

)

[

i

]

=

i

j

C

[

j

]

=

i

j

x

y

=

j

A

[

x

]

×

B

[

y

]

=

i

(

x

y

)

A

[

x

]

×

B

[

y

]

=

i

x

A

[

x

]

×

i

y

B

[

y

]

=

F

W

T

(

A

)

[

i

]

×

F

W

T

(

B

)

[

i

]

\begin{aligned} FWT(C)[i]&=\sum_{i\in j}C[j]\\ &=\sum_{i\in j}\sum_{x|y=j}A[x]\times B[y]\\ &=\sum_{i\in(x|y)}A[x]\times B[y]\\ &=\sum_{i\in x}A[x]\times\sum_{i\in y}B[y]\\ &=FWT(A)[i]\times FWT(B)[i] \end{aligned}

FWT(C)[i]​=i∈j∑​C[j]=i∈j∑​x∣y=j∑​A[x]×B[y]=i∈(x∣y)∑​A[x]×B[y]=i∈x∑​A[x]×i∈y∑​B[y]=FWT(A)[i]×FWT(B)[i]​

几乎就是一样的qwq

逆变换

也是很简单的将加号变减号。

证明: 我们现在已知

F

W

T

(

A

)

0

,

F

W

T

(

A

)

1

FWT(A)_0,FWT(A)_1

FWT(A)0​,FWT(A)1​,要求

A

0

,

A

1

A_0,A_1

A0​,A1​。

F

W

T

(

A

)

1

=

F

W

T

(

A

1

)

\because FWT(A)_1=FWT(A_1)

∵FWT(A)1​=FWT(A1​)

A

1

=

I

F

W

T

(

F

W

T

(

A

1

)

)

=

I

F

W

T

(

F

W

T

(

A

)

1

)

\therefore A_1=IFWT(FWT(A_1))=IFWT(FWT(A)_1)

∴A1​=IFWT(FWT(A1​))=IFWT(FWT(A)1​)

F

W

T

(

A

)

0

=

F

W

T

(

A

0

)

+

F

W

T

(

A

1

)

\because FWT(A)_0=FWT(A_0)+FWT(A_1)

∵FWT(A)0​=FWT(A0​)+FWT(A1​),即

F

W

T

(

A

0

)

=

F

W

T

(

A

)

1

F

W

T

(

A

)

0

FWT(A_0)=FWT(A)_1-FWT(A)_0

FWT(A0​)=FWT(A)1​−FWT(A)0​

A

0

=

I

F

W

T

(

F

W

T

(

A

0

)

)

=

I

F

W

T

(

F

W

T

(

A

)

0

F

W

T

(

A

)

1

)

\therefore A_0=IFWT(FWT(A_0))=IFWT(FWT(A)_0-FWT(A)_1)

∴A0​=IFWT(FWT(A0​))=IFWT(FWT(A)0​−FWT(A)1​)

代码实现:

void FWT_and(ll *f,int type)

{

for(int mid=1;mid

for(int block=mid<<1,j=0;j

for(int i=j;i

f[i]=(f[i]+f[i+mid]*type+mod)%mod;

}

异或卷积

这个东西才是真正的

F

W

T

FWT

FWT,求法都奇奇怪怪的。

卷积的公式是这样的:

C

[

k

]

=

i

Λ

j

=

k

A

[

i

]

×

B

[

j

]

C[k]=\sum\limits_{i\Lambda j=k}A[i]\times B[j]

C[k]=iΛj=k∑​A[i]×B[j]。

正变换

首先摒弃上面带来的一些奇奇怪怪的想法,因为异或卷积的正变换没有用到异或,完全没有。

c

(

i

)

c(i)

c(i) 表示

i

i

i 的二进制有多少个

1

1

1,如

c

(

3

)

=

2

c(3)=2

c(3)=2。

奇怪的定义:

F

W

T

(

A

)

[

i

]

=

j

=

0

2

n

1

(

1

)

c

(

i

&

j

)

A

[

j

]

FWT(A)[i]=\sum\limits_{j=0}^{2^n-1}(-1)^{c(i\&j)}A[j]

FWT(A)[i]=j=0∑2n−1​(−1)c(i&j)A[j],也可以写成

F

W

T

(

A

)

[

i

]

=

(

c

(

i

&

j

)

m

o

d

2

=

0

A

[

j

]

)

(

c

(

i

&

k

)

m

o

d

2

=

1

A

[

k

]

)

FWT(A)[i]=(\sum\limits_{c(i\&j)\bmod 2=0}A[j])-(\sum\limits_{c(i\&k)\bmod 2=1}A[k])

FWT(A)[i]=(c(i&j)mod2=0∑​A[j])−(c(i&k)mod2=1∑​A[k])。

没错,是

&

\&

& 不是

Λ

\Lambda

Λ。不用管为什么,看下去就知道了,重点是记住定义。

递归公式:

F

W

T

(

A

)

=

{

(

F

W

T

(

A

0

)

+

F

W

T

(

A

1

)

,

F

W

T

(

A

0

)

F

W

T

(

A

1

)

)

(

n

>

0

)

A

(

n

=

0

)

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

FWT(A)={(FWT(A0​)+FWT(A1​),FWT(A0​)−FWT(A1​))A​(n>0)(n=0)​

怎么样,是不是有种见了鬼的感觉qwq

但是实际上不难理解。

证明

依然忽略

n

=

0

n=0

n=0 时的情况~

此时要理解,求出来的

F

W

T

(

A

1

)

FWT(A_1)

FWT(A1​) 并没有考虑到他是

A

A

A 的右半部分,即最高位的

1

1

1 是没有考虑的,也就是说,求

F

W

T

(

A

1

)

FWT(A_1)

FWT(A1​) 时下标是

0

0

0 ~

2

n

1

1

2^{n-1}-1

2n−1−1,而不是

2

n

1

2^{n-1}

2n−1 ~

2

n

1

2^n-1

2n−1。

剩下的我们从左到右看:

首先

F

W

T

(

A

)

0

=

F

W

T

(

A

0

)

+

F

W

T

(

A

1

)

FWT(A)_0=FWT(A_0)+FWT(A_1)

FWT(A)0​=FWT(A0​)+FWT(A1​),因为

F

W

T

(

A

)

0

FWT(A)_0

FWT(A)0​ 是左半部分,于是最高位是

0

0

0,所以不管是和左半部分做与运算还是与右半部分做与运算,最高位都是

0

0

0,所以直接把左右两边的贡献加起来即可。

F

W

T

(

A

)

1

FWT(A)_1

FWT(A)1​ 比较特殊,他是右半部分,所以他与右半部分做与运算时,最高位多出来一个

1

1

1,而这是

F

W

T

(

A

1

)

FWT(A_1)

FWT(A1​) 没有考虑到的,如果多了个

1

1

1 的话,回看上面的定义,

c

(

i

&

j

)

c(i\&j)

c(i&j) 就会乘多一个

1

-1

−1,所以

F

W

T

(

A

1

)

FWT(A_1)

FWT(A1​) 的贡献是负的。而

F

W

T

(

A

0

)

FWT(A_0)

FWT(A0​) 无所谓,由于它本身就在左半部分,不会多出最高位的

1

1

1,所以贡献是正的。

求解证明

这里就用到异或了,以及用到了一个性质(描述有点长qwq,不想看的可以直接看下面的柿子):

i

i

i 与

k

k

k 的

1

1

1 的数量的奇偶性异或

j

j

j 与

k

k

k 的

1

1

1 的数量的奇偶性等于

i

i

i 异或

j

j

j 再与

k

k

k 的

1

1

1 的数量的奇偶性相同。

用数学柿子来表示的话,设

P

(

i

)

P(i)

P(i) 表示

i

i

i 的奇偶性,当

i

i

i 是奇数时

P

(

i

)

=

1

P(i)=1

P(i)=1,当

i

i

i 是偶数时

P

(

i

)

=

0

P(i)=0

P(i)=0,那么这个性质就是:

P

(

c

(

i

&

k

)

)

Λ

P

(

c

(

j

&

k

)

)

=

P

(

c

(

(

i

Λ

j

)

&

k

)

)

P(c(i\&k))\Lambda P(c(j\&k))=P(c((i\Lambda j)\&k))

P(c(i&k))ΛP(c(j&k))=P(c((iΛj)&k))

为了严谨,证明还是要有的(其实随便手玩一下就懂了,很简单):

考虑

i

,

j

,

k

i,j,k

i,j,k 的某一位,记为

x

,

y

,

z

x,y,z

x,y,z(注意,是同一位),那么有两种情况(已经尽力压缩了qwq,怕多了各位不看呀,下面这些看起来繁琐的东西其实逻辑很简单的,静心细看就好):

x

,

y

x,y

x,y 都等于或不等于

z

z

z(即

x

=

y

x=y

x=y)。那么

i

&

k

i\&k

i&k 和

j

&

k

j\&k

j&k 的这一位相同,所以

c

(

i

&

k

)

c(i\&k)

c(i&k) 和

c

(

j

&

k

)

c(j\&k)

c(j&k) 同时

+

1

+1

+1 或

+

0

+0

+0,

P

(

c

(

i

&

k

)

)

Λ

P

(

c

(

j

&

k

)

)

P(c(i\&k))\Lambda P(c(j\&k))

P(c(i&k))ΛP(c(j&k)) 的值不变。再看等式右边,

i

Λ

j

i\Lambda j

iΛj 的这一位为

0

0

0,那么

(

i

Λ

j

)

&

k

(i\Lambda j)\&k

(iΛj)&k 的这一位就是

0

0

0,对

c

(

(

i

Λ

j

)

&

k

)

c((i\Lambda j)\&k)

c((iΛj)&k) 没有贡献,所以

P

(

c

(

(

i

Λ

j

)

&

k

)

)

P(c((i\Lambda j)\&k))

P(c((iΛj)&k)) 也不会变,等式成立。

x

,

y

x,y

x,y 一个等于

z

z

z,一个不等于

z

z

z(即

x

y

x\neq y

x​=y)。假如

z

=

0

z=0

z=0,那么参照情况

1

1

1,很容易知道此时两边又是不会发生变化的。如果

z

=

1

z=1

z=1,此时

i

&

k

i\&k

i&k 和

j

&

k

j\&k

j&k 的这一位不同,所以

c

(

i

&

k

)

c(i\&k)

c(i&k) 和

c

(

j

&

k

)

c(j\&k)

c(j&k) 一个

+

1

+1

+1,一个

+

0

+0

+0,那么等式左边就会发生变化。而右边因为

i

Λ

j

i\Lambda j

iΛj 和

k

k

k 的这一位同时为

1

1

1,所以

c

(

(

i

Λ

j

)

&

k

)

c((i\Lambda j)\&k)

c((iΛj)&k) 会

+

1

+1

+1,那么等式右边也会发生变化。等式两边同时变化,等式依然成立。

接下来就是求解的证明了,还是像上面那样大力展开(自己手(luan)推的,要是错了告知一下谢谢啦qwq):

F

W

T

(

C

)

[

i

]

=

j

=

0

2

n

1

(

1

)

c

(

i

&

j

)

C

[

j

]

=

j

=

0

2

n

1

(

1

)

c

(

i

&

j

)

x

Λ

y

=

j

A

[

x

]

×

B

[

y

]

=

x

=

0

2

n

1

y

=

0

2

n

1

A

[

x

]

×

B

[

y

]

×

(

1

)

c

(

i

&

(

x

Λ

y

)

)

\begin{aligned} FWT(C)[i]&=\sum\limits_{j=0}^{2^n-1}(-1)^{c(i\&j)}C[j]\\ &=\sum\limits_{j=0}^{2^n-1}(-1)^{c(i\&j)}\sum_{x\Lambda y=j} A[x]\times B[y]\\ &=\sum_{x=0}^{2^n-1}\sum_{y=0}^{2^n-1}A[x]\times B[y]\times(-1)^{c(i\&(x\Lambda y))} \end{aligned}

FWT(C)[i]​=j=0∑2n−1​(−1)c(i&j)C[j]=j=0∑2n−1​(−1)c(i&j)xΛy=j∑​A[x]×B[y]=x=0∑2n−1​y=0∑2n−1​A[x]×B[y]×(−1)c(i&(xΛy))​

诶!仔细观察发现,我们只在意

c

(

i

&

(

x

Λ

y

)

)

c(i\&(x\Lambda y))

c(i&(xΛy)) 的奇偶性,因为他是

1

-1

−1 的指数,所以我们不妨在外面套一个

P

P

P,显然是不影响答案的。

=

x

=

0

2

n

1

y

=

0

2

n

1

A

[

x

]

×

B

[

y

]

×

(

1

)

P

(

c

(

i

&

(

x

Λ

y

)

)

)

=\sum_{x=0}^{2^n-1}\sum_{y=0}^{2^n-1}A[x]\times B[y]\times(-1)^{P(c(i\&(x\Lambda y)))}

=x=0∑2n−1​y=0∑2n−1​A[x]×B[y]×(−1)P(c(i&(xΛy)))

这不就是上面性质里的样子吗!于是我们可以愉快的拆开啦:

=

x

=

0

2

n

1

y

=

0

2

n

1

A

[

x

]

×

B

[

y

]

×

(

1

)

P

(

c

(

i

&

x

)

)

 

Λ

 

P

(

c

(

i

&

y

)

)

=\sum_{x=0}^{2^n-1}\sum_{y=0}^{2^n-1}A[x]\times B[y]\times(-1)^{P(c(i\&x))~\Lambda ~P(c(i\&y))}

=x=0∑2n−1​y=0∑2n−1​A[x]×B[y]×(−1)P(c(i&x)) Λ P(c(i&y))

仔细观察下面的柿子,是不是有什么规律?

(

1

)

0

Λ

0

=

   

1

=

(

1

)

0

+

0

(-1)^{0\Lambda 0}=~~~1=(-1)^{0+0}

(−1)0Λ0=   1=(−1)0+0

(

1

)

0

Λ

1

=

1

=

(

1

)

0

+

1

(-1)^{0\Lambda 1}=-1=(-1)^{0+1}

(−1)0Λ1=−1=(−1)0+1

(

1

)

1

Λ

0

=

1

=

(

1

)

1

+

0

(-1)^{1\Lambda 0}=-1=(-1)^{1+0}

(−1)1Λ0=−1=(−1)1+0

(

1

)

1

Λ

1

=

   

1

=

(

1

)

1

+

1

(-1)^{1\Lambda 1}=~~~1=(-1)^{1+1}

(−1)1Λ1=   1=(−1)1+1

没错!将指数里的

Λ

\Lambda

Λ 换成

+

+

+ 并不影响答案!

接下来就可以顺理成章的证明下去了。

=

x

=

0

2

n

1

y

=

0

2

n

1

A

[

x

]

×

B

[

y

]

×

(

1

)

P

(

c

(

i

&

x

)

)

+

P

(

c

(

i

&

y

)

)

=

x

=

0

2

n

1

y

=

0

2

n

1

A

[

x

]

×

B

[

y

]

×

(

1

)

P

(

c

(

i

&

x

)

)

×

(

1

)

P

(

c

(

i

&

y

)

)

=

x

=

0

2

n

1

A

[

x

]

×

(

1

)

P

(

c

(

i

&

x

)

)

×

y

=

0

2

n

1

B

[

y

]

×

(

1

)

P

(

c

(

i

&

y

)

)

=

F

W

T

(

A

)

[

i

]

×

F

W

T

(

B

)

[

i

]

\begin{aligned} &=\sum_{x=0}^{2^n-1}\sum_{y=0}^{2^n-1}A[x]\times B[y]\times(-1)^{P(c(i\&x))+P(c(i\&y))}\\ &=\sum_{x=0}^{2^n-1}\sum_{y=0}^{2^n-1}A[x]\times B[y]\times(-1)^{P(c(i\&x))}\times(-1)^{P(c(i\&y))}\\ &=\sum_{x=0}^{2^n-1}A[x]\times (-1)^{P(c(i\&x))} \times \sum_{y=0}^{2^n-1}B[y]\times (-1)^{P(c(i\&y))}\\ &=FWT(A)[i]\times FWT(B)[i] \end{aligned}

​=x=0∑2n−1​y=0∑2n−1​A[x]×B[y]×(−1)P(c(i&x))+P(c(i&y))=x=0∑2n−1​y=0∑2n−1​A[x]×B[y]×(−1)P(c(i&x))×(−1)P(c(i&y))=x=0∑2n−1​A[x]×(−1)P(c(i&x))×y=0∑2n−1​B[y]×(−1)P(c(i&y))=FWT(A)[i]×FWT(B)[i]​

逆变换

这个就稍微跟上面不一样的,不过一样的是都很容易理解~

A

=

F

W

T

(

A

)

A'=FWT(A)

A′=FWT(A),那么逆变换递推公式就是:

{

(

I

F

W

T

(

A

0

)

+

I

F

W

T

(

A

1

)

2

,

I

F

W

T

(

A

0

)

I

F

W

T

(

A

1

)

2

)

(

n

>

0

)

A

(

n

=

0

)

\begin{cases} (\frac {IFWT(A'_0)+IFWT(A'_1)} 2,\frac {IFWT(A'_0)-IFWT(A'_1)} 2) & (n>0)\\ A' & (n=0) \end{cases}

{(2IFWT(A0′​)+IFWT(A1′​)​,2IFWT(A0′​)−IFWT(A1′​)​)A′​(n>0)(n=0)​

证明: 现在已知

F

W

T

(

A

)

0

,

F

W

T

(

A

)

1

FWT(A)_0,FWT(A)_1

FWT(A)0​,FWT(A)1​,求

A

0

,

A

1

A_0,A_1

A0​,A1​。

F

W

T

(

A

)

0

=

F

W

T

(

A

0

)

+

F

W

T

(

A

1

)

,

F

W

T

(

A

)

1

=

F

W

T

(

A

0

)

F

W

T

(

A

1

)

\because FWT(A)_0=FWT(A_0)+FWT(A_1),FWT(A)_1=FWT(A_0)-FWT(A_1)

∵FWT(A)0​=FWT(A0​)+FWT(A1​),FWT(A)1​=FWT(A0​)−FWT(A1​)

F

W

T

(

A

0

)

=

F

W

T

(

A

)

0

+

F

W

T

(

A

)

1

2

,

F

W

T

(

A

1

)

=

F

W

T

(

A

)

0

F

W

T

(

A

)

1

2

\therefore FWT(A_0)=\frac {FWT(A)_0+FWT(A)_1} 2,FWT(A_1)=\frac {FWT(A)_0-FWT(A)_1} 2

∴FWT(A0​)=2FWT(A)0​+FWT(A)1​​,FWT(A1​)=2FWT(A)0​−FWT(A)1​​

A

0

=

I

F

W

T

(

F

W

T

(

A

0

)

)

=

I

F

W

T

(

F

W

T

(

A

)

0

+

F

W

T

(

A

)

1

2

)

\therefore A_0=IFWT(FWT(A_0))=IFWT(\frac {FWT(A)_0+FWT(A)_1} 2)

∴A0​=IFWT(FWT(A0​))=IFWT(2FWT(A)0​+FWT(A)1​​)

    

A

1

=

I

F

W

T

(

F

W

T

(

A

1

)

)

=

I

F

W

T

(

F

W

T

(

A

)

0

F

W

T

(

A

)

1

2

)

~~~~A_1=IFWT(FWT(A_1))=IFWT(\frac {FWT(A)_0-FWT(A)_1} 2)

    A1​=IFWT(FWT(A1​))=IFWT(2FWT(A)0​−FWT(A)1​​)

代码实际上也没比上面的麻烦多少:

void FWT_xor(ll *f,int type)

{

for(int mid=1;mid

for(int block=mid<<1,j=0;j

for(int i=j;i

{

ll x=f[i],y=f[i+mid];

f[i]=(x+y)%mod*(type==1?1:inv_2)%mod;

f[i+mid]=(x-y+mod)%mod*(type==1?1:inv_2)%mod;

}

}

模板题

题目传送门

#include

#include

#define ll long long

#define mod 998244353

#define maxn 1<<18

int n;

ll a[maxn],b[maxn],A[maxn],B[maxn];

void FWT_or(ll *f,int type)

{

for(int mid=1;mid

for(int block=mid<<1,j=0;j

for(int i=j;i

f[i+mid]=(f[i+mid]+f[i]*type+mod)%mod;

}

void FWT_and(ll *f,int type)

{

for(int mid=1;mid

for(int block=mid<<1,j=0;j

for(int i=j;i

f[i]=(f[i]+f[i+mid]*type+mod)%mod;

}

int inv_2=499122177;

void FWT_xor(ll *f,int type)

{

for(int mid=1;mid

for(int block=mid<<1,j=0;j

for(int i=j;i

{

ll x=f[i],y=f[i+mid];

f[i]=(x+y)%mod*(type==1?1:inv_2)%mod;

f[i+mid]=(x-y+mod)%mod*(type==1?1:inv_2)%mod;

}

}

void work(void (*FWT)(ll *f,int type))//将函数作为参数传入

{

for(int i=0;i

FWT(a,1);FWT(b,1);

for(int i=0;i

FWT(a,-1);

for(int i=0;i

printf("\n");

}

int main()

{

scanf("%d",&n);n=1<

for(int i=0;i

for(int i=0;i

work(FWT_or);work(FWT_and);work(FWT_xor);

}

优惠劵

Hypoc_

关注

关注

15

点赞

28

收藏

觉得还不错?

一键收藏

知道了

7

评论

快速沃尔什变换(FWT)详详详解

介绍我们以前常见的多项式乘法长这个亚子:C[k]=∑i+j=kA[i]×B[j]C[k]=\sum_{i+j=k}A[i]\times B[j]C[k]=i+j=k∑​A[i]×B[j]而 FWTFWTFWT 用来处理的,与 FFTFFTFFT 稍稍不同,是这样的卷积:C[k]=∑i⊕j=kA[i]×B[j]C[k]=\sum_{i\oplus j=k}A[i]\times B[j]...

复制链接

扫一扫

专栏目录

离散沃尔什变换及其快速算法

03-23

描述了离散沃尔什变换及其快速算法,是关于数字信号处理里的,包括了哈达玛的相关内容

aaa.zip_沃尔什变换

09-23

wash函数的功能通过编程解决了离散沃尔什变换的一个算法。该算法通过三十二阶沃尔什变换矩阵对输入的向量进行离散沃尔什变换

7 条评论

您还未登录,请先

登录

后发表或查看评论

快速沃尔什变换(FWT)

最新发布

Video_game的博客

01-21

869

其中, ⊕表示任意位运算符号(与(&),或(|),异或(^)之一)的形式,相乘后再用逆变换转换成多项式形式。是用于解决对下表进行位运算卷积问题的方法。采用分治策略,每一次将多项式分为左半边。且就是说可以通过按位相乘的方式,以。接下来要解决的是如何求一个多项式的。如图所示,先分别计算两边的值,由于。以下会对三种位运算符号分别推导。其一定满足左半边下标最高位为。更确切地说,给定两个多项式。,右半边下标最高位为。,所以最终合并的结果为。同上或的递推式,由于。

基于快速沃尔什变换和启发搜索的一种序列拼接方法

10-04

基于快速沃尔什变换和启发搜索的一种序列拼接方法

图像 快速沃尔什变换 c++

03-01

图像 快速沃尔什变换 c++ 适合初学者学习

利用快速沃尔什变换算法对数字图像或矩阵作快速变换

08-01

利用数字图像处理的快速沃尔什变换算法对数字图像或矩阵进行快速沃尔什变换

快速沃尔什变换(FWT)介绍

HolmiumJiang的博客

07-24

4671

快速沃尔什变换(FWT)介绍

众所周知,FFT可以有效地解决如下的问题

A=(a1,…,an)B=(b1,...,bn)C=(c1,...,cn)ck=∑i+j=kai∗bj

A=(a_1,\dots,a_n)\\

B=(b_1,...,b_n)\\

C=(c_1,...,c_n)\\

c_k=\sum_{i+j=k}a_i*b_j\\

A=(a1​,…,an​)B=(b1​,...,bn​)C=(c1​,...,cn​)ck​=i+j=k∑​ai​∗bj​

但事实上,把求和号里的条件里的“+”换成与、或、

快速沃尔什变换(FWT)

dygxczn的博客

04-26

487

FWT 是一个用来快速求出下标进行位运算卷积的方法。

FWT(快速沃尔什变换)

qq_35975367的博客

10-23

1958

待更。。

【学习笔记】快速沃尔什变换(FWT)

C20181503csy的博客

08-06

976

FWT

位运算卷积(FWT)

ez_lcw的博客

12-15

3608

本文大量参考了:

command_block 的博客:位运算卷积(FWT) & 集合幂级数

FWT 概论

定义位运算卷积:C[k]=∑i⊕j=kA[i]B[j]C[k]=\sum\limits_{i\oplus j=k}A[i]B[j]C[k]=i⊕j=k∑​A[i]B[j],记作 C=A∗BC=A*BC=A∗B,其中 $\oplus $ 为某一位运算。

设 A,BA,BA,B 下标的范围都是 [0,n−1][0,n-1][0,n−1] 且满足 nnn 是 222 的幂,那么卷出来 CCC 的下

快速沃尔什变换(FWT)及K进制异或卷积&快速子集变换(FST)讲解

weixin_33847182的博客

03-13

475

前言:

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

快速沃尔什变化(FWT)介绍

zhshrs的博客

02-02

4837

快速沃尔什变化(FWT)

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

tanjunming2020的博客

04-25

1779

## 快速沃尔什变换

对于求上面这类运算的卷积,我们可以用$FFT$的思路,将两个多项式先正变换,再按位相乘,最后逆变换回来。这就是$FWT$的思路。

【总结】FWT算法

氧化钠的博客

03-12

7450

前言:

作为FFT又一个衍生算法,FWT相对(NTT)来说比较特殊,特殊在它的运算全部是逻辑运算(即与,或,异或等),这也导致FWT的代码看上去和FFT并不类似,但总的来说FWT是一个相对容易的算法(只不过需要背一些东西)。

算法介绍

FFT算法,是用于优化卷积,而FWT是用于优化逻辑运算卷积。形如下图:

C[x⊕y]=∑A[x]B[y]C[x⊕y]=∑A[x]B[y]C[x\op...

FWT(Fast Walsh-Hadamard Transform)

Freopen的博客

12-20

1710

去年听GZMdalao讲FWT,第一句就是:构造这玩意的人是神(经病)_{(经病)}(经病)​吧。

其实还好。。。。。。

FFT向我们提供了一个思路来解决卷积问题,那就是对于多项式(数组)构造一个(可逆)变换FFT(A),使得:

FFT(A)[i]∗FFT(B)[i]=FFT(A∘B)[i]FFT(A)[i] * FFT(B)[i] = FFT(A \circ B)[i]FFT(A)[i]∗F...

FWT学习笔记

Master.Yi的博客

05-14

619

拓展:

给出序列a1,...,ana_1,...,a_na1​,...,an​以及ppp,求i∈[1,n]i\in[1,n]i∈[1,n]的(1+pxai)(1+px^{a_i})(1+pxai​)的异或卷积。

分治FWT复杂度太高。

考虑(1+pxa)(1+px^{a})(1+pxa)的对应的多项式bixib_ix^ibi​xi的FWTFWTFWT变换:ci=∑j(−1)d(i&j)bjc_i=\sum\limits_{j}(-1)^{d(i\&j)}b_jci​=j∑​(−1)d(i&a

(转载)快速沃尔什变换(FWT) (知识整理+板子总结)

Code92007的博客

03-02

597

思路来源

https://blog.csdn.net/john123741/article/details/76576925

https://www.cnblogs.com/cjyyb/p/9065615.html(含and、or、xor具体证明过程)

强力安利思路来源博主的博客,翻了好几个都看不懂,这两位比较清晰……

用途

a数组如果在第i位为1,b数组在第j位为1,

那么卷积...

基于快速沃尔什变换的特征提取matlab代码

06-02

以下是基于快速沃尔什变换(FWT)的特征提取Matlab代码示例:

```matlab

% 生成随机信号

x = randn(1, 1024);

% 计算FWT系数

fwt_x = fwht(x);

% 选择前50个系数作为特征

features = fwt_x(1:50);

```

这段代码首先生成一个长度为1024的随机信号,然后使用Matlab内置的函数`fwht`计算它的FWT系数。最后,选择前50个系数作为特征,存储在一个向量中。

需要注意的是,快速沃尔什变换的实现方式有多种,不同的实现方式计算的FWT系数可能略有不同。因此,在实际应用中,需要根据具体情况选择合适的FWT实现方式。

“相关推荐”对你有帮助么?

非常没帮助

没帮助

一般

有帮助

非常有帮助

提交

Hypoc_

CSDN认证博客专家

CSDN认证企业博客

码龄6年

暂无认证

537

原创

3万+

周排名

7万+

总排名

47万+

访问

等级

8610

积分

285

粉丝

888

获赞

247

评论

1725

收藏

私信

关注

热门文章

线性基详解

36293

c++中struct构造函数

35896

约瑟夫问题详解

31094

C++中struct的用法

29345

裴蜀定理

23004

分类专栏

题解_杂

304篇

网络流24题

21篇

UR系列

18篇

博弈论

2篇

算法小结区

35篇

计算几何

4篇

2篇

多项式

19篇

字符串

7篇

数据结构

11篇

图论

4篇

搜索

2篇

平衡树

2篇

网络流

5篇

其他知识的一些小结

10篇

数论

25篇

c++的各种功能

4篇

GSS系列题解

8篇

比赛

41篇

随笔小结

12篇

最新评论

SG函数及SG定理详解+证明

Hare_me:

写的真好,终于看懂了

因数个数函数(d)的一点笔记

m0_74045100:

线性筛有问题

线性基详解

lingruibang:

虽然讲的都懂了,但还是不知道有啥用,怎么用。但大佬还是很有实力的

C++中struct的用法

hpmhpm303:

c里面是不可以的,必须要struct,c++里面可以

快速沃尔什变换(FWT)详详详解

INF_512:

"这玩意丑的很……相信没人想看的qwq",我想看qwq

您愿意向朋友推荐“博客详情页”吗?

强烈不推荐

不推荐

一般般

推荐

强烈推荐

提交

最新文章

2023牛客暑期多校第三场部分题解

2023牛客暑期多校第六场部分题解

2023牛客暑期多校第五场部分题解

2023年10篇

2021年31篇

2020年279篇

2019年162篇

2018年55篇

目录

目录

分类专栏

题解_杂

304篇

网络流24题

21篇

UR系列

18篇

博弈论

2篇

算法小结区

35篇

计算几何

4篇

2篇

多项式

19篇

字符串

7篇

数据结构

11篇

图论

4篇

搜索

2篇

平衡树

2篇

网络流

5篇

其他知识的一些小结

10篇

数论

25篇

c++的各种功能

4篇

GSS系列题解

8篇

比赛

41篇

随笔小结

12篇

目录

评论 7

被折叠的  条评论

为什么被折叠?

到【灌水乐园】发言

查看更多评论

添加红包

祝福语

请填写红包祝福语或标题

红包数量

红包个数最小为10个

红包总金额

红包金额最低5元

余额支付

当前余额3.43元

前往充值 >

需支付:10.00元

取消

确定

下一步

知道了

成就一亿技术人!

领取后你会自动成为博主和红包主的粉丝

规则

hope_wisdom 发出的红包

实付元

使用余额支付

点击重新获取

扫码支付

钱包余额

0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

FWT 详解 知识点_fwttuimn-CSDN博客

>

FWT 详解 知识点_fwttuimn-CSDN博客

FWT 详解 知识点

最新推荐文章于 2023-12-28 12:11:38 发布

neither_nor

最新推荐文章于 2023-12-28 12:11:38 发布

阅读量9.9k

收藏

11

点赞数

20

分类专栏:

BZOJ

课件、论文、知识点讲解

FWT

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/neither_nor/article/details/60335099

版权

BZOJ

同时被 3 个专栏收录

382 篇文章

1 订阅

订阅专栏

课件、论文、知识点讲解

4 篇文章

0 订阅

订阅专栏

FWT

3 篇文章

0 订阅

订阅专栏

前言(扯淡,可以跳过):

其实去年清华集训之后就想写这篇文章了……但是写了一会发现有点说不明白话……于是受限于语文水平一直没有写。前几天给人当面讲了一遍,感觉大概可以BB明白些了……

picks的博客里就写着fwt怎么做,然而他并没有写为什么这样是对的

去年清华集训后的某一天,ljss和我一起刷清华集训题,然后他突然跑来问我一道题:给定数组a,求数组b,使得b[i]=对于所有的j满足j|i==i,sigma a[j]

YY了一会我YY了一个分治做法,然后ljss告诉我这是清华集训D1T2的简化版,然后又告诉我这题是FWT,我想了一会我YY的做法这尼玛不就是FWT的正变换么

然后和ljss一起进行了半天瞎YY,终于YY出了FWT到底是个什么jb玩意

发现我写出了问题还请及时评论-_-

FWT能干什么:

FWT可以对于两个数组a和b,求出他们的位运算卷积c,使得c[k]=对于所有的i和j 满足 i位运算j等于k sigma a[i]*b[j]

我们先讲与卷积和或卷积,最后再讲异或卷积

一个简单的问题:

先考虑一下前言中提到的问题

给定数组a,求数组b,使得b[i]=对于所有的j满足j|i==i,sigma a[j]

我们考虑按位分治,先把数组长度用0补到2的幂

先不考虑最高位,那么我们可以把长度为2^l的原数组按最高位为0和最高位为1分为两部分

递归处理这两部分,假设我们现在已经得到了对于所有最高位为0的下标求的b数组b0和对所有最高位为1的下标求的b数组b1,他们的长度均为2^(l-1)

那么我们现在考虑最高位的影响。我们把计入最高位影响之后的长度为2^l的b数组分为左右两部分,记为bn0和bn1,即最高位为0的部分和最高位为1的部分,他们的长度也都为2^(l-1)

那么对于任意的i和j,如果j|i不等于i,给i和j添加一个最高位之后的j|i一定也不等于i,所以bn0[i]和bn1[i]只与b0[i]和b1[i]有关

而如果j|i等于i,那么假设给i添加最高位ih,给j添加最高位jh,添加最高位后j|i是否等于i就只与jh|ih是否等于ih有关

那么我们显然就可以得到bn0[i]=b0[i],bn1[i]=b0[i]+b1[i]

觉得不显然可以YY一下

如果是要求使得b[i]=对于所有的j满足j&i==i,sigma a[j]的话,那么就是bn0[0]=b0[i]+b1[i],bn1[i]=b1[i]

这样的话我们就可以在n log n的时间内求出b数组

我们会发现这个做法事实上就是或卷积的正变换

在后面我们也将求b数组叫做正变换

或卷积、与卷积的原理:

或卷积和与卷积事实上基于如下原理:

i&k==k并且j&k==k等价于(i&j)&k==k

i|k==k并且j|k==k等价于(i|j)|k==k

那么如果要求数组a和数组b的与卷积或者或卷积,我们就只需要求出a的正变换a'和b的正变换b',然后另c'[i]=a'[i]*b'[i],那么容易发现c'就是a和b的卷积做正变换的结果

那么我们现在就只需要考虑给你一个正变换之后的结果,如何做逆变换求出原数组

逆变换:

逆变换的过程事实上就是一个解密的过程,而正变换相当于加密

我们还是按位考虑,在正变换的时候,我们令bn0[i]=b0[i],bn1[i]=b0[i]+b1[i],那么如果你现在知道的是bn0和bn1,那么容易知道b0[i]=bn0[i],b1[i]=bn1[i]-bn0[i]

与运算的逆变换同理

然后再递归左右两边即可

你可能会产生疑惑:在进行正变换的时候我们先递归左右两边再考虑这一位,那么在逆变换的时候是否需要先考虑这一位再递归两边呢

而事实上因为每一位都是等价的,所以逆变换的时候一样可以先递归再考虑这一位,顺序无所谓

异或卷积:

异或这个东西和与还有或就不太一样……所以我们YY了挺长时间才YY明白异或卷积是个什么鬼畜

异或卷积基于如下原理:

定义i和j之间的奇偶性为:i&j中为1的位数的奇偶性,若为偶数则奇偶性是0,若为奇数则奇偶性是1

那么i和k的奇偶性异或j和k的奇偶性等于i^j和k的奇偶性

证明显然,YY一下即可

那么我们令数组a做正变换之后的数组b的意义是:b[i]=(sigma j满足i和j的奇偶性==0 a[j] )-(sigma j满足i和j的奇偶性==1 a[j])

那么如果要求a和b的异或卷积c,另a做完正变换为a',b做完正变换为b',c'[i]=a'[i]*b'[i],那么c'恰好就是c做正变换之后的结果

证明显然,如果觉得不显然可以稍微YY一下就明白了

那么就考虑一下如何做正变换和逆变换就好了,还是按位分治

在正变换的时候,令bn0[i]=b0[i]+b1[i],bn1[i]=b0[i]-b1[i]

在逆变换的时候,令b0[i]=(bn0[i]+bn1[i])/2,b1[i]=(bn0[i]-bn1[i])/2

正确性显然

完结撒花>_M

优惠劵

neither_nor

关注

关注

20

点赞

11

收藏

觉得还不错?

一键收藏

知道了

13

评论

FWT 详解 知识点

前言(扯淡,可以跳过):其实去年清华集训之后就想写这篇文章了……但是写了一会发现有点说不明白话……于是受限于语文水平一直没有写。前几天给人当面讲了一遍,感觉大概可以BB明白些了……picks的博客里就写着fwt怎么做,然而他并没有写为什么这样是对的去年清华集训后的某一天,ljss和我一起刷清华集训题,然后他突然跑来问我一道题:给定数组a,求数组b,使得b[i]=对于所有的j满足j|

复制链接

扫一扫

专栏目录

FWT.rar_fwt

09-21

用51单片机控制两相混合式步进电机,程序用单片机C语言编制而成

【总结】FWT算法

氧化钠的博客

03-12

7450

前言:

作为FFT又一个衍生算法,FWT相对(NTT)来说比较特殊,特殊在它的运算全部是逻辑运算(即与,或,异或等),这也导致FWT的代码看上去和FFT并不类似,但总的来说FWT是一个相对容易的算法(只不过需要背一些东西)。

算法介绍

FFT算法,是用于优化卷积,而FWT是用于优化逻辑运算卷积。形如下图:

C[x⊕y]=∑A[x]B[y]C[x⊕y]=∑A[x]B[y]C[x\op...

13 条评论

您还未登录,请先

登录

后发表或查看评论

uniapp 多端保存图片的逻辑(app端,普通浏览器端,微信内置浏览器端)

hcy5201314521的博客

12-28

5843

问题描述:移动端保存图片时,直接保存仅能保存当前屏幕大小的图片;需求需要保存指定区域的内容。与uniapp的renderjs解决。

百度语音合成data:audio/x-mpeg;base64转mp3

热门推荐

z19980115的博客

06-24

47万+

百度语音base64转mp3

FWT(快速沃尔什变换)

qq_35975367的博客

10-23

1958

待更。。

快速沃尔什变换(FWT)介绍

HolmiumJiang的博客

07-24

4671

快速沃尔什变换(FWT)介绍

众所周知,FFT可以有效地解决如下的问题

A=(a1,…,an)B=(b1,...,bn)C=(c1,...,cn)ck=∑i+j=kai∗bj

A=(a_1,\dots,a_n)\\

B=(b_1,...,b_n)\\

C=(c_1,...,c_n)\\

c_k=\sum_{i+j=k}a_i*b_j\\

A=(a1​,…,an​)B=(b1​,...,bn​)C=(c1​,...,cn​)ck​=i+j=k∑​ai​∗bj​

但事实上,把求和号里的条件里的“+”换成与、或、

快速沃尔什变换(FWT)

dygxczn的博客

04-26

487

FWT 是一个用来快速求出下标进行位运算卷积的方法。

位运算卷积(FWT)

ez_lcw的博客

12-15

3608

本文大量参考了:

command_block 的博客:位运算卷积(FWT) & 集合幂级数

FWT 概论

定义位运算卷积:C[k]=∑i⊕j=kA[i]B[j]C[k]=\sum\limits_{i\oplus j=k}A[i]B[j]C[k]=i⊕j=k∑​A[i]B[j],记作 C=A∗BC=A*BC=A∗B,其中 $\oplus $ 为某一位运算。

设 A,BA,BA,B 下标的范围都是 [0,n−1][0,n-1][0,n−1] 且满足 nnn 是 222 的幂,那么卷出来 CCC 的下

【学习笔记】快速沃尔什变换(FWT)

C20181503csy的博客

08-06

976

FWT

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

tanjunming2020的博客

04-25

1779

## 快速沃尔什变换

对于求上面这类运算的卷积,我们可以用$FFT$的思路,将两个多项式先正变换,再按位相乘,最后逆变换回来。这就是$FWT$的思路。

FWT.rar_fwt_mathematica 图

09-24

用mathematica实现蜂窝图的作图

FWT.rar_fast convolution_fwt

09-23

利用c++实现快速沃尔什变换,可以进行异或卷积,原理和FFT类似

FWT.zip_FWT2_fwt_zip

09-20

Fast Wavelet Transform FWT

C code.zip_fwt_zip

07-15

Fast Wavelet Transform ...

LCT维护子树信息(子树信息LCT) LCT维护边权(边权LCT) 知识点讲解

neither_nor

10-31

9220

扯淡(前言)

众所周知LCT可以支持关于点权的链修改,换根,LINK,CUT和查询链信息操作,但是总有那么些神犇(毒瘤)出题人会让你在支持链修改,换根,LINK和CUT操作的情况下去支持子树查询,或者维护关于边权的链修改,换根,LINK,CUT和链查询。网上似乎讲解这两种LCT写法的blog比较少或者不怎么能搜到?总之我来写一发

(LCT基础知识回顾)

为了方便说话先说一下下面可能出现的

manacher 后缀数组 AC自动机 回文自动机 知识点讲解 课件

neither_nor

08-28

712

光老师让我讲课……于是我就做了课件……因为是PPT所以懒得一页一页粘上来,就发度娘盘链接吧-_-

包含简单的知识点讲解以及例题~(有例题没题解有卵用啊-_-)

http://pan.baidu.com/s/1jIdgQB8

pandas_plink-1.2.26-cp37-cp37m-macosx_10_6_intel.whl

最新发布

03-15

Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

gensim-3.6.0-cp36-cp36m-manylinux1_i686.whl.zip

03-15

gensim-3.6.0-cp36-cp36m-manylinux1_i686.whl.zip

fwt usb driver

07-30

FWT(固定无线终端) USB驱动程序是用于支持FWT设备与计算机之间进行数据传输和通信的软件。FWT是一种将移动电话信号转换为有线电话信号,并通过USB接口与计算机连接的设备。

FWT USB驱动程序在安装后,可以实现以下功能:

1. 数据传输:FWT设备可以通过USB接口与计算机进行数据传输,例如传输文件、短信等。

2. 通信功能:FWT设备可以通过USB接口与计算机进行电话通信,实现拨号、接听、挂断等功能。

3. 设备管理:FWT USB驱动程序可以提供对FWT设备的管理和控制,例如设置网络参数、调整音量等。

FWT USB驱动程序的安装步骤如下:

1. 下载驱动程序:从FWT设备的官方网站或其他可信来源下载适用于您的操作系统的驱动程序。

2. 连接设备:将FWT设备通过USB接口连接到计算机上。

3. 安装驱动程序:双击下载的驱动程序安装包,按照提示完成驱动程序的安装。

4. 启动设备:在安装完成后,重新启动计算机,并确保FWT设备已连接且驱动程序正常加载。

FWT USB驱动程序的安装完成后,您就可以通过计算机与FWT设备进行数据传输和通信了。请记得定期检查是否有新的驱动程序可用,并根据需要进行更新,以确保设备在使用过程中的兼容性和稳定性。

“相关推荐”对你有帮助么?

非常没帮助

没帮助

一般

有帮助

非常有帮助

提交

neither_nor

CSDN认证博客专家

CSDN认证企业博客

码龄8年

暂无认证

401

原创

12万+

周排名

216万+

总排名

41万+

访问

等级

8367

积分

134

粉丝

134

获赞

205

评论

109

收藏

私信

关注

热门文章

NOI2017搞基记

10538

FWT 详解 知识点

9951

LCT维护子树信息(子树信息LCT) LCT维护边权(边权LCT) 知识点讲解

9220

OIer JCY

6880

BZOJ4543/BZOJ3522 [POI2014]Hotel加强版

4354

分类专栏

BZOJ

382篇

UOJ

5篇

课件、论文、知识点讲解

4篇

扯淡

11篇

OI无关

1篇

神题-_-

4篇

DP、递推

84篇

仙人掌

3篇

莫队

6篇

分块

5篇

rmq

1篇

后缀自动机

10篇

主席树

16篇

树倍增

5篇

找规律

5篇

单调栈

11篇

trie

2篇

矩阵乘法

11篇

LCT

14篇

斜率优化

1篇

费用流

7篇

FFT

7篇

线性基

2篇

贪心

22篇

凸包

3篇

二分

16篇

并查集

9篇

倍增

5篇

网络流

9篇

线段树

41篇

扫描线

3篇

dfs序

5篇

CDQ分治

2篇

数位DP

5篇

BFS

3篇

线段树分治

1篇

DFS

5篇

生成函数

4篇

高精度

5篇

FWT

3篇

虚树

2篇

快速乘

1篇

构造

7篇

matrix-tree

2篇

高斯消元

8篇

容斥原理

8篇

可持久化trie

2篇

替罪羊树

2篇

数学

16篇

组合数取模

6篇

01分数规划

2篇

树链剖分

7篇

动点spfa

1篇

可并堆

2篇

最短路

6篇

最小生成树

4篇

调和级数

3篇

分治

4篇

NTT

1篇

原根

1篇

burnside、ploya

3篇

爆搜

2篇

KDT

4篇

manacher

4篇

单调队列

2篇

tarjan

2篇

哈夫曼

1篇

树套树

1篇

二维线段树

3篇

kmp

2篇

树状数组

8篇

splay

2篇

hash

9篇

BSGS

1篇

(计算)几何

2篇

树分治

1篇

三分

2篇

floyd

2篇

启发式合并

3篇

博弈论

4篇

ETT

2篇

莫比乌斯反演

1篇

随机

2篇

treap

1篇

斯坦纳树

2篇

整体二分

1篇

DP套DP

1篇

最新评论

BZOJ4347 [POI2016]Nim z utrudnieniem

ChaseLegend:

TLE 6个点 78分

BZOJ4048/3928 [Cerc2014] Outer space invaders

qq_53145847:

好像是可以让 dp[i][j] 表示 [i,j] 区间内答案的

UOJ#218 【UNR #1】火车管理

LightningUZ:

orz

无缘

memset0:

静流真可爱

NOI2017搞基记

LightningUZ:

noip rank1!%%

最新文章

无缘

逝随春花——OIer JCY 后续

新年扯皮以及一些比较正经的东西

2018年3篇

2017年120篇

2016年279篇

目录

目录

分类专栏

BZOJ

382篇

UOJ

5篇

课件、论文、知识点讲解

4篇

扯淡

11篇

OI无关

1篇

神题-_-

4篇

DP、递推

84篇

仙人掌

3篇

莫队

6篇

分块

5篇

rmq

1篇

后缀自动机

10篇

主席树

16篇

树倍增

5篇

找规律

5篇

单调栈

11篇

trie

2篇

矩阵乘法

11篇

LCT

14篇

斜率优化

1篇

费用流

7篇

FFT

7篇

线性基

2篇

贪心

22篇

凸包

3篇

二分

16篇

并查集

9篇

倍增

5篇

网络流

9篇

线段树

41篇

扫描线

3篇

dfs序

5篇

CDQ分治

2篇

数位DP

5篇

BFS

3篇

线段树分治

1篇

DFS

5篇

生成函数

4篇

高精度

5篇

FWT

3篇

虚树

2篇

快速乘

1篇

构造

7篇

matrix-tree

2篇

高斯消元

8篇

容斥原理

8篇

可持久化trie

2篇

替罪羊树

2篇

数学

16篇

组合数取模

6篇

01分数规划

2篇

树链剖分

7篇

动点spfa

1篇

可并堆

2篇

最短路

6篇

最小生成树

4篇

调和级数

3篇

分治

4篇

NTT

1篇

原根

1篇

burnside、ploya

3篇

爆搜

2篇

KDT

4篇

manacher

4篇

单调队列

2篇

tarjan

2篇

哈夫曼

1篇

树套树

1篇

二维线段树

3篇

kmp

2篇

树状数组

8篇

splay

2篇

hash

9篇

BSGS

1篇

(计算)几何

2篇

树分治

1篇

三分

2篇

floyd

2篇

启发式合并

3篇

博弈论

4篇

ETT

2篇

莫比乌斯反演

1篇

随机

2篇

treap

1篇

斯坦纳树

2篇

整体二分

1篇

DP套DP

1篇

目录

评论 13

被折叠的  条评论

为什么被折叠?

到【灌水乐园】发言

查看更多评论

添加红包

祝福语

请填写红包祝福语或标题

红包数量

红包个数最小为10个

红包总金额

红包金额最低5元

余额支付

当前余额3.43元

前往充值 >

需支付:10.00元

取消

确定

下一步

知道了

成就一亿技术人!

领取后你会自动成为博主和红包主的粉丝

规则

hope_wisdom 发出的红包

实付元

使用余额支付

点击重新获取

扫码支付

钱包余额

0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

FWT,FST入门 - crashed - 博客园

FWT,FST入门 - crashed - 博客园

会员

周边

新闻

博问

AI培训

云市场

所有博客

当前博客

我的博客

我的园子

账号设置

简洁模式 ...

退出登录

注册

登录

crashed

博客园

首页

新随笔

联系

订阅

管理

FWT,FST入门

什么是 FWT

FWT 全称为 " 快速沃尔什变换: Fast Walsh Transform " 。可以用于解决位运算卷积的问题。

什么叫位运算卷积呢?我们考虑普通的卷积,即:

\[C_k=\sum_{i+j=k}A_iB_j

\]位运算卷积就是下标为位运算的卷积(此处与和或用 C++ 记号,异或用\(\oplus\)):

\[\begin{aligned}\text{与卷积:}&C_k=\sum_{i\&j=k}A_iB_j\\\text{或卷积:}&C_k=\sum_{i|j=k}A_iB_j\\\text{异或卷积:}&C_k=\sum_{i\oplus j=k}A_iB_j\end{aligned}

\]FWT

为了方便,以下我们假设所有向量长度都相等,为\(2\)的整幂,即长度\(n=2^m\)。高位以 0 补齐。

设一个向量\(A\)经过 FWT 之后得到了\(FWT(A)\), FWT 的最终目标就是满足:\(FWT(C)=FWT(A)\cdot FWT(B)\),其中的点乘表示向量的每一位相乘:\(A\cdot B=(A_0B_0,A_1B_1,...,A_iB_i,...)\)。

FWT 针对三种位运算有各自的处理方法:

或卷积

我们发现或运算存在如下的性质:

\[(j|i=i)\land (k|i=i)\Rightarrow (j|k)|i=i

\]如果将二进制理解为一个 01 集合,我们就可以用集合并的方式理解上面的性质。发现这其实是一个伪分配律。

根据这个性质我们可以进行构造:

\[a_i=\sum_{j|i=i}A_j\\b_i=\sum_{j|i=i}B_j\\c_i=\sum_{j|i=i}C_j

\]那么可以发现:

\[\begin{aligned}

a_ib_i

&=\sum_{j|i=i}A_j\times \sum_{k|i=i}B_k\\

&=\sum_{j|i=i}\sum_{k|i=i}A_jB_k\\

&=\sum_{(j|k)|i=i}A_jB_k\\

&=c_i

\end{aligned}

\]这样做了对应乘法之后就可以得到\(c\),再进行一次逆变换就可以得到\(C\)。

因此问题变成了怎么进行这样的变换。

考虑一种分治(或者称为 DP )的做法:

\(f(i,j)\):满足仅有低\(i\)位可能与\(j\)不同的,且与\(j\)或后得到\(j\)的下标所对应的数的和。

或者可以被描述为:

\[f(i,j)=\sum_{\lfloor\frac k{2^i}\rfloor=\lfloor\frac j{2^i}\rfloor,k|j=j} a_k

\]考虑如何进行转移,即从\(f(i-1)\)转移到\(f(i)\)。这种情况下只有第\(i\)位解除了限制。根据或的性质,如果第\(i\)位为 0 ,那么第\(i\)位或操作之后仍需要是 0 ,就只能从第\(i\)位为 0 的\(f(i,j)\)转移来;如果第\(i\)位为 1 ,那么第\(i\)位或操作总得到是 1 ,就可以不考虑第\(i\)位,从\(f(i,j)\)和\(f(i,j+2^i)\)转移来。

放个图片理解一下:

顺便可以得到转移为:

正变换:

\[\begin{aligned}

f(i,j)&=f(i-1,j)\\

f(i,j+2^i)&=f(i-1,j)+f(i-1,j+2^i)

\end{aligned}

\]逆变换就是将特殊贡献扣除:

\[\begin{aligned}

f(i,j)&=f(i+1,j)\\

f(i,j+2^i)&=f(i+1,j+2^i)-f(i+1,j)

\end{aligned}

\]可以发现\(f(0,i)=A_i\),且这个转移可以滚动数组优化。

这样的 FWT 就是\(O(n\log_2n)\)。

与卷积

与卷积与或卷积十分相似,因此可以用类似的方法分析。这里只给出状态和转移:

\[f(i,j)=\sum_{\lfloor\frac k{2^i}\rfloor=\lfloor\frac j{2^i}\rfloor,k\&j=j} a_k

\]正变换:

\[\begin{aligned}

f(i,j)&=f(i-1,j)+f(i-1,j+2^i)\\

f(i,j+2^i)&=f(i-1,j+2^i)

\end{aligned}

\]逆变换:

\[\begin{aligned}

f(i,j)&=f(i+1,j)-f(i+1,j+2^i)\\

f(i,j+2^i)&=f(i+1,j+2^i)

\end{aligned}

\]异或卷积

我们同样考虑异或的性质。

设\(count(i)\)为\(i\)的二进制中\(1\)的位数,\(i\otimes j=count(i\&j)\bmod 2\)则异或有性质:

\[(i\otimes j)\oplus(i\otimes k)=i\otimes (j\oplus k)

\]即奇偶性相等。设\(count(j\&i)=a,count(k\&i)=b,count(j\&k\&i)=c\),则左侧奇偶性由\(a+b\)决定,右侧奇偶性由\(a+b-2c\)决定,可以发现两侧的奇偶性相等。

说起奇偶性,我们可以想到\(-1\)的幂。于是设:

\[\begin{aligned}

a_i=\sum_j(-1)^{i\otimes j}A_j\\

b_i=\sum_j(-1)^{i\otimes j}B_j\\

c_i=\sum_j(-1)^{i\otimes j}C_j

\end{aligned}

\]然后就可以看看这样转换后乘起来的结果:

\[\begin{aligned}

a_ib_i

&=\sum_j(-1)^{i\otimes j}A_j\times \sum_k(-1)^{i\otimes k}B_k\\

&=\sum_{i\otimes j=0}\sum_{i\otimes k=0}A_jB_k-\sum_{i\otimes j=1}\sum_{i\otimes k=0}A_jB_k-\sum_{i\otimes j=0}\sum_{i\otimes k=1}A_jB_k+\sum_{i\otimes j=1}\sum_{i\otimes k=1}A_jB_k\\

&=\sum_{i\otimes (j\oplus k)=0}A_jB_k-\sum_{i\otimes (j\oplus k)=1}A_jB_k\\

&=\sum_p(-1)^{i\otimes p}\sum_{j\oplus k=p}A_jB_k\\

&=\sum_p(-1)^{i\otimes p}C_p\\

&=c_i

\end{aligned}

\]我们达成了目的。接下来就看看怎么变换。继续考虑 DP :

\[f(i,j)=\sum_{\lfloor\frac k {2^i}\rfloor=\lfloor \frac j {2^i}\rfloor}(-1)^{j\otimes k}a_k

\]可以发现,从\(f(i-1)\)转到\(f(i)\)的时候,只有第\(i\)位都是\(1\)才会令\(j\otimes k\)改变奇偶性,即多乘上一个 -1 。

这样转移,最终\(j\otimes k=0\)的情况就会被乘上偶数次 -1 ,而\(j\otimes k=1\)的情况就会被乘上奇数次 -1 ,最终答案就是正确的。

按照这样,正变换:

\[\begin{aligned}

f(i,j)&=f(i-1,j)+f(i-1,j+2^i)\\

f(i,j+2^i)&=f(i-1,j)-f(i-1,j+2^i)

\end{aligned}

\]逆变换,用到了小学奥数的 " 和差问题 " 的结论:

\[\begin{aligned}

f(i,j)&=\frac{f(i+1,j)+f(i+1,j+2^i)} 2\\

f(i,j+2^i)&=\frac{f(i+1,j)-f(i+1,j+2^i)} 2

\end{aligned}

\]需要注意的是,异或卷积的逆变换还有一个 " 类 FFT " 的写法,即逆变换只比正变换在最后多除一个\(n\)(事实上异或 FWT 和 FFT 有很多相似处,可以在 K 进制 FWT 中找到答案)。

例题

洛谷P4717。三种 FWT 全家桶。

参考代码:

const int mod = 998244353, inv2 = 499122177;

const int MAXSIZ = 5e5 + 5;

int A[MAXSIZ], B[MAXSIZ], C[MAXSIZ], a[MAXSIZ], b[MAXSIZ];

int N, M;

int fix( const int x ) { return ( x % mod + mod ) % mod; }

namespace OR

{

void FWT( int *f, const int m )

{

for( int s = 2 ; s <= M ; s <<= 1 )

for( int i = 0, t = s >> 1 ; i < M ; i += s )

for( int j = i ; j < i + t ; j ++ )

f[j + t] = fix( f[j + t] + f[j] * m ) % mod;

}

}

namespace AND

{

void FWT( int *f, const int m )

{

for( int s = 2 ; s <= M ; s <<= 1 )

for( int i = 0, t = s >> 1 ; i < M ; i += s )

for( int j = i ; j < i + t ; j ++ )

f[j] = fix( f[j] + f[j + t] * m ) % mod;

}

}

namespace XOR

{

void FWT( int *f, const int m )

{

int t1, t2;

for( int s = 2 ; s <= M ; s <<= 1 )

for( int i = 0, t = s >> 1 ; i < M ; i += s )

for( int j = i ; j < i + t ; j ++ )

{

t1 = f[j], t2 = f[j + t];

if( m > 0 )

f[j] = ( t1 + t2 ) % mod,

f[j + t] = fix( t1 - t2 );

else

f[j] = 1ll * ( t1 + t2 ) % mod * inv2 % mod,

f[j + t] = 1ll * fix( t1 - t2 ) * inv2 % mod;

}

}

}

void cal( void ( *fwt ) ( int*, int ) ) //函数指针的写法,主要是方便。

{

for( int i = 0 ; i < M ; i ++ ) A[i] = a[i], B[i] = b[i];

fwt( A, 1 ), fwt( B, 1 );

for( int i = 0 ; i < M ; i ++ ) C[i] = 1ll * A[i] * B[i] % mod;

fwt( C, -1 );

for( int i = 0 ; i < M ; i ++ ) write( C[i] ), putchar( i == M - 1 ? '\n' : ' ' );

}

FST

FST 怎么做

它听着不妙。

快速子集变换 FST 解决的是一类子集卷积的问题,即:

\[f(U)=\sum_{S,T\subseteq U, S\cup T=U, S\cap T=\varnothing} g(S)\times h(T)

\]这个卷积和或卷积的区别在于,或卷积可以有交集(并不要求\(j\& k=0\)),然而子集卷积不可以有。

注意到这个限制在子集卷积中等价于\(|S|+|T|=|U|\)。因此我们可以给状态加上一维限制大小:

\(f(i,U)\):大小为\(i\)的集合\(U\)的所有子集的贡献,\(g\)和\(h\)同理转换。

这个信息可以直接用 FWT 正变换得到。

因此有转移:

\[f(i,U)=\sum_j^i\sum_{S\cup T=U}g(i,S)\times h(i-j,T)

\]转移完成后需要 FWT 逆变换回来,再将不符合要求(集合大小不匹配)的清除。

例题

[CF914G]Sum The Fibonacci, FWT + FST ,附赠题解一篇。

posted @

2020-03-29 23:38 

crashed 

阅读(418) 

评论(0) 

编辑 

收藏 

举报

会员力量,点亮园子希望

刷新页面返回顶部

公告

Copyright © 2024 crashed

Powered by .NET 8.0 on Kubernetes

浅谈快速沃尔什变换(FWT)&快速莫比乌斯变换(FMT)_fast mobius transform-CSDN博客

>

浅谈快速沃尔什变换(FWT)&快速莫比乌斯变换(FMT)_fast mobius transform-CSDN博客

浅谈快速沃尔什变换(FWT)&快速莫比乌斯变换(FMT)

最新推荐文章于 2023-04-26 17:36:00 发布

偶耶XJX

最新推荐文章于 2023-04-26 17:36:00 发布

阅读量3.5k

收藏

5

点赞数

2

分类专栏:

竞赛经验总结

文章标签:

算法

卷积

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/weixin_43960287/article/details/113620658

版权

竞赛经验总结

专栏收录该内容

35 篇文章

6 订阅

订阅专栏

目录

快速沃尔什变换(FWT)

按位或卷积

按位与卷积

按位异或卷积

一点性质/优化

快速莫比乌斯变换(FMT)

按位或FMT

按位与FMT

两者比较

快速沃尔什变换(FWT)

顾名思义,这是一种对数组的变换,而且和FFT是基本思想相同,即求,“o”是一种卷积,把A、B变换为A‘、B’,使满足,最后把C‘转换回C。

沃尔什变换主要有三种:

按位或卷积

,(数组长度n默认为2的次幂)求C数组。

“浅谈”,我们就直接上公式好了。

该变换为,是按位与,显然有:

根据定义知道,暴力求该变换是的,怎么优化呢?

对于一个数组A,其下标为(0~n-1),,那么数组前一半的下标为(二进制),后一半下标为,那么对于和(),假设前者是所有下标为的数的和,那么后者一定是下标为、的数的和(、分别代指若干种01序列),

规范地说就是,把A数组割裂为前后两半,(0~n/2-1)部分构成数组A0,(n/2~n-1)部分构成数组A1(在A1中的下标变为(0~n/2-1)),那么(),

(),

所以我们得到了该算法的核心:求出和,然后遍历求出和,进而求得,

这是递推打法,类比FFT和NTT:

inline void FWTOR(int*a,int n){

for(int k=2;k<=n;k<<=1)//从下往上合并

for(int i=0;i

for(int j=i;j>1);j++)

a[j+(k>>1)]=(a[j+(k>>1)]+a[j])%MOD;//FWT(A)(i+n/2)=FWT(A0)(i)+FWT(A1)(i)

//FWT(A)(i)=FWT(A0)(i),此时直接不管它

}

简要解释一下,原本递归到最底层后会有n个长度为1的数组,而长度为1的数组的FWT就是它本身,所以由下往上合并为长度为2、长度为4、一直到长度为n的数组,就是要求的FWT(A)。

那么逆变换怎么搞呢?

考虑倒着做整个过程,,(),

所以,,然后从上往下把它倒着转换回去:

inline void IFWTOR(int*a,int n){

for(int k=n;k>1;k>>=1)//从上往下倒推

for(int i=0;i

for(int j=i;j>1);j++)

a[j+(k>>1)]=(a[j+(k>>1)]-a[j]+MOD)%MOD;

}

按位与卷积

,求C数组。

和按位或很相似,相信读者们自己就能轻松推导,

该变换为:,同样的推导:

同样地,根据该变换的性质,把A分裂为A0和A1,有,(),

倒着做的时候:,

inline void FWTAND(int*a,int n){

for(int k=2;k<=n;k<<=1)

for(int i=0;i

for(int j=i;j>1);j++)

a[j]=(a[j]+a[j+(k>>1)])%MOD;

}

inline void IFWTAND(int*a,int n){

for(int k=n;k>1;k>>=1)

for(int i=0;i

for(int j=i;j>1);j++)

a[j]=(a[j]-a[j+(k>>1)]+MOD)%MOD;

}

按位异或卷积

(是按位异或),求C数组。

这个就不好搞了,一般人很难想出来,但是沃尔什大佬不一样,他想出了如下变换:

,其中表示x的二进制中1的个数取模2,也就是1的个数的奇偶性,

这个公式要倒着证:

观察上式,发现结构是00+11-01-10,而0^0=1^1=0,0^1=1^0=1;

然后有个结论:

所以原式可以继续变换:

至此,我们发现它满足了沃尔什变换的性质!

第二步,用分治优化它,

我们故技重施,把A分成前一半A0和后一半A1;

已知任给,,有

所以容易得到:,

逆推式:,

inline void FWTXOR(int*a,int n){

for(int k=2;k<=n;k<<=1)

for(int i=0;i

for(int j=i;j>1);j++)

a0=a[j],a1=a[j+(k>>1)],a[j]=(a0+a1)%MOD,a[j+(k>>1)]=(a0-a1+MOD)%MOD;

}

//此处应有个快速幂

inline void IFWTXOR(int*a,int n){

ll in2=ksm(2,MOD-2,MOD),a0,a1;//in2为2的逆元

for(int k=n;k>1;k>>=1)

for(int i=0;i

for(int j=i;j>1);j++)

a0=a[j],a1=a[j+(k>>1)],a[j]=(a0+a1)%MOD*in2%MOD,a[j+(k>>1)]=(a0-a1+MOD)%MOD*in2%MOD;

}

一点性质/优化

一点很常用的性质:k的枚举顺序可以任意调换。

具体来说,每个代码(包括每个逆变换)循环的开头一行在“for(int k=2;k<=n;k<<=1)”和"for(int k=n;k>1;k>>=1)"之间互换,得到的数列完全相同。

笔者手打了好多草稿,发现这个性质单用FWT的思想真的不方便证,就只好举个例子感性说明一下:

给定数组A:

A: a b c d

进行一次FWTXOR变换,k从小到大:

A: a b c d

A: a+b a-b c+d c-d

A: a+b+c+d a-b+c-d a+b-c-d a-b-c+d

k从大到小:

A: a b c d

A: a+c b+d a-c b-d

A: a+b+c+d a-b+c-d a+b-c-d a-b-c+d

结果完全一样,OR变换和AND变换也一样。

读者们可以自行造数据测试,或者学学巨佬们推一下(我菜不行

有了这个性质,我们就可以统一正变换和逆变换的枚举顺序,然后把他们写在一个函数里:

//所有函数中传入inv=1表示正变换,-1表示逆变换

inline void FWTOR(int*a,int n,int inv){ //按位或

for(int k=2;k<=n;k<<=1)//k的枚举从大到小和从小到大,结果是完全一样的

for(int i=0;i

for(int j=i;j>1);j++)

a[j+(k>>1)]=(a[j+(k>>1)]+a[j]*inv+MOD)%MOD;

}

inline void FWTAND(int*a,int n,int inv){ //按位与

for(int k=2;k<=n;k<<=1)

for(int i=0;i

for(int j=i;j>1);j++)

a[j]=(a[j]+a[j+(k>>1)]*inv+MOD)%MOD;

}

//此处应有个快速幂

inline void FWTXOR(int*a,int n,int inv){ //异或

int in2=inv>0?1:ksm(2,MOD-2,MOD),a0,a1;

for(int k=2;k<=n;k<<=1)

for(int i=0;i

for(int j=i;j>1);j++)

a0=a[j],a1=a[j+(k>>1)],a[j]=(a0+a1)%MOD*in2%MOD,a[j+(k>>1)]=(a0-a1+MOD)%MOD*in2%MOD;

}

然后,据某位对计算机原理了如指掌的专业人士说,一般k的枚举顺序从大到小可以比从小到大枚举快几百毫秒(某常数大师直呼**,效果我还没试过,读者感兴趣的可以试一试

快速莫比乌斯变换(FMT)

这个变换用处不是很大,几乎就只有代替FWTOR和FWTAND的功能,它的原理是基于DP。

莫比乌斯变换本来有很严谨的定义(好像和什么集合幂级数有关),但是这里我们只根据它的实际用处通俗地讲。

笔者看到有的博客里说FWTOR和FWTAND的本质是FMT,这其实是在众多博客的混淆下搞错了,它们推导原理都不同(分治和DP)

(也有可能是我搞错了,反正我看到的博客中一半支持其本质FMT,一半又持不同观点,教练看了代码也没说什么)

按位或FMT

,和沃尔什变换的按位或除了优化方法之外完全一样,

它的优化方法是设表示 x 在二进制第 i 位以后部分和 j 一样、第 i 位以前部分和 j 进行按位与后等于 x 的的和,

则显然有

并且(设数组长度),

所以调整枚举顺序,把第一个下标省略后,再在原数组上进行DP,就得到该变换的完整过程:

inline void FMTOR(int*a,int n){

for(int k=1;k

for(int i=0;i

if(~i&k)a[i|k]=(a[i|k]+a[i])%MOD;

}

如何进行逆变换呢?

反过来,我们设表示 x 在二进制第 i 位以前部分和 j 一样、第 i 位以后部分和 j 进行按位与后等于 x 的的和,

则可以得到

设数组长度,有,

一样地省略第一个下标,得到逆变换:

inline void IFMTOR(int*a,int n){

for(int k=1;k

for(int i=0;i

if(~i&k)a[i|k]=(a[i|k]-a[i]+MOD)%MOD;

}

正变换和逆变换只有一个加减号的区别,所以可以合并为一个函数:

inline void FMTOR(int*a,int n,int inv){

for(int k=1;k

for(int i=0;i

if(~i&k)a[i|k]=(a[i|k]+a[i]*inv+MOD)%MOD;

}

这一般比FWT常数小,而且好打

按位与FMT

,也和沃尔什变换是一样的定义,DP式子和按位或有一点区别:

设表示 x 在二进制第 i 位以后部分和 j 一样、第 i 位以前部分和 j 进行按位与后等于 x 的的和,

逆变换式子表示 x 在二进制第 i 位以前部分和 j 一样、第 i 位以后部分和 j 进行按位与后等于 x 的的和,

一样的省去第一个下标,只不过枚举顺序反过来,从n-1到0:

inline void FMTAND(int*a,int n,int inv){//正变换和逆变换

for(int k=1;k

for(int i=n-1;i>=0;i--)

if(i&k)a[i^k]=(a[i^k]+a[i]*inv+MOD)%MOD;

}

两者比较

FWT和FMT时间复杂度一样,都是,几乎没有额外空间。

此文章之前的版本说莫比乌斯变换无法解决按位异或,那其实是笔误,

其实细心的读者可以发现,FWT和FMT在程序运行过程中每一步对数组A干的事情是完全一样的,仅仅是代码长得不一样。为什么不一样?因为思路不同。

从代码角度看,FWT就是FMT,FMT就是FWT,思想不同但是走到了同一条路上(难怪总有人把它们搞混),

由于在推DP的过程中,我们发现完全可以定义一个枚举顺序和正变换一样的DP来达到逆变换,而FWT和FMT本质上操作是一样的,所以终于可以解释为什么FWT的枚举顺序也可以任意倒了。

由上面的发现,我们甚至可以强行把FWTXOR打成长得像FMT的样子:

inline void FMTXOR(int*a,int n,int inv){

int in2=inv>0?1:ksm(2,MOD-2,MOD),a0,a1;

for(int k=1;k

for(int i=0;i

if(~i&k)a0=a[i],a1=a[i|k],a[i]=(a0+a1)%MOD*in2%MOD,a[i|k]=(a0-a1+MOD)%MOD*in2%MOD;

}

这么说来,按位异或变换也应该有个DP式子,但是叫不叫莫比乌斯变换就不清楚了。

另外,由于DP打法的灵活性,FMT能更方便地解决n不是2的次幂的情况,只需再加个特判。

优惠劵

偶耶XJX

关注

关注

2

点赞

5

收藏

觉得还不错?

一键收藏

知道了

0

评论

浅谈快速沃尔什变换(FWT)&快速莫比乌斯变换(FMT)

快速沃尔什变换(FWT),顾名思义,这是一种对数组的变换,而且和FFT是基本思想相同。快速莫比乌斯变换(FMT),代码用处不是很大,几乎就只有代替FWT按位或和FWT按位与的功能,它的原理是基于DP。

复制链接

扫一扫

专栏目录

aaa.zip_沃尔什变换

09-23

wash函数的功能通过编程解决了离散沃尔什变换的一个算法。该算法通过三十二阶沃尔什变换矩阵对输入的向量进行离散沃尔什变换

基于快速沃尔什变换和启发搜索的一种序列拼接方法

10-04

基于快速沃尔什变换和启发搜索的一种序列拼接方法

参与评论

您还未登录,请先

登录

后发表或查看评论

利用快速沃尔什变换算法对数字图像或矩阵作快速变换

08-01

利用数字图像处理的快速沃尔什变换算法对数字图像或矩阵进行快速沃尔什变换

离散沃尔什变换及其快速算法

03-23

描述了离散沃尔什变换及其快速算法,是关于数字信号处理里的,包括了哈达玛的相关内容

VLC 参数详解

flyhelloword的博客

10-30

8587

用法: vlc [选项] [流] …

您可以在命令行中指定多个流。

它们将被加入播放列表队列。

指定的首个项目将被首先播放。

选项风格:

–选项 用于设置程序执行期间的全局选项。

-选项 单字母版本的全局 --选项。

:选项 仅对此选项之前的单条流生效,

且优先级高于先前的设置。

流媒体 MRL 语法:

[[协议][/分流]????/]URL[#[标题][:章节][-[标题][:章节]]]

[:选项=值 …]

许多全局 --选项 也可作为 MRL 特定的 :选项 使用。

可指定多组 :选项=值。

UR

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

L183287669的博客

12-11

322

  最近在学FWT,抽点时间出来把这个算法总结一下。

  快速沃尔什变换(Fast Walsh-Hadamard Transform),简称FWT。是快速完成集合卷积运算的一种算法。

  主要功能是求:,其中为集合运算符。

  就像FFT一样,FWT是对数组的一种变换,我们称数组X的变换为FWT(X)。

  所以FWT的核心思想是:

    为了求得C=A★B,我们瞎搞搞...

多项式算法3:FWT\FMT(快速沃尔什变换\快速莫比乌斯变换)

ha_ing的博客

05-15

441

多项式算法3:FWT\FMT(快速沃尔什变换\快速莫比乌斯变换)

快速莫比乌斯变换(FMT)

07-09

946

快速莫比乌斯变换(FMT)

原文出处:虞大的博客。此仅作蒟蒻本人复习用~

给定两个长度为n的序列 \(a_0, a_1, \cdots, a_{n-1}\)和\(b_0, b_1, \cdots, b_{n-1}\),你需要求出一个序列\(c_0, c_1, \cdots, c_{n-1}\),其中\(c_k\)满足:\(c_k = \sum\limits_{i \mid j = k}...

【学习笔记】快速沃尔什变换(FWT)

C20181503csy的博客

08-06

976

FWT

快速沃尔什变换(FWT)

dygxczn的博客

04-26

487

FWT 是一个用来快速求出下标进行位运算卷积的方法。

图像 快速沃尔什变换 c++

03-01

图像 快速沃尔什变换 c++ 适合初学者学习

反演与集合幂级数

weixin_30522183的博客

04-19

529

VFK的PPT堪称经典,迄今为止看过的最好的一篇,真的是体现出数学精妙。

主要就是各个方面的融汇贯通,涉及的知识有:复数,莫比乌斯反演,矩阵变换,微积分初步等。

直接进入正题。

转载请注明出处:http://www.cnblogs.com/HocRiser/p/8886806.html

目录:

  一.反演定义

  二.二项式反演

  三.莫比乌斯反演

  四.集合幂级数

...

FFT 专题讲解

weixin_30445169的博客

08-19

71

FFT是什么?

FFT是快速傅里叶变换(fast Fourier transform)的简称。在ACM领域主要是用来快速求解多项式乘法的算法,

在信号领域也有很大用途

基础知识

卷积

举个例子,给你两个向量 \(a (a_0, a_1, a_2), b(b_0, b_1, b_2)\)

a和b的卷积就是$ ( a_0b_0, a_1b_0+a_0b_1, a_2b_0+a_1b_1+a_0b_...

Mobius transform

hjwang1的专栏

09-27

269

ref:https://baike.baidu.com/item/%E9%BB%98%E6%AF%94%E4%B9%8C%E6%96%AF%E5%8F%98%E6%8D%A2/18902824?fr=aladdin

Mobius transform

沃尔什变换

grllery的博客

04-06

9096

沃尔什变换

快速莫比乌斯变换

qq_43520313的博客

03-06

368

莫比乌斯变换

定义函数fff的莫比乌斯变换为f^\hat ff^​

f^S=∑T⊆SfT

\hat f_S=\sum_{T\subseteq S}f_T

f^​S​=T⊆S∑​fT​

则有莫比乌斯反演

fS=∑T⊆S(−1)∣S∣−∣T∣f^T

f_S=\sum_{T\subseteq S}(-1)^{|S|-|T|}\hat f_T

fS​=T⊆S∑​(−1)∣S∣−∣T∣f^​T​

快速莫比乌斯变换FMT

考虑如何快速快速进行莫比乌斯变换和反演。

设f^Si=∑T⊆S[(S−T)⊆{1,2,...,i

快速沃尔什变换(FWT)介绍

HolmiumJiang的博客

07-24

4671

快速沃尔什变换(FWT)介绍

众所周知,FFT可以有效地解决如下的问题

A=(a1,…,an)B=(b1,...,bn)C=(c1,...,cn)ck=∑i+j=kai∗bj

A=(a_1,\dots,a_n)\\

B=(b_1,...,b_n)\\

C=(c_1,...,c_n)\\

c_k=\sum_{i+j=k}a_i*b_j\\

A=(a1​,…,an​)B=(b1​,...,bn​)C=(c1​,...,cn​)ck​=i+j=k∑​ai​∗bj​

但事实上,把求和号里的条件里的“+”换成与、或、

模板:快速莫比乌斯变换(FMT)+快速沃尔什变换(FWT)(多项式)

BUG_Creater_jie的博客

01-04

740

下标进行位运算而不是简单加法的卷积时的处理方法

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

tanjunming2020的博客

04-25

1779

## 快速沃尔什变换

对于求上面这类运算的卷积,我们可以用$FFT$的思路,将两个多项式先正变换,再按位相乘,最后逆变换回来。这就是$FWT$的思路。

基于快速沃尔什变换的特征提取matlab代码

最新发布

06-02

以下是基于快速沃尔什变换(FWT)的特征提取Matlab代码示例:

```matlab

% 生成随机信号

x = randn(1, 1024);

% 计算FWT系数

fwt_x = fwht(x);

% 选择前50个系数作为特征

features = fwt_x(1:50);

```

这段代码首先生成一个长度为1024的随机信号,然后使用Matlab内置的函数`fwht`计算它的FWT系数。最后,选择前50个系数作为特征,存储在一个向量中。

需要注意的是,快速沃尔什变换的实现方式有多种,不同的实现方式计算的FWT系数可能略有不同。因此,在实际应用中,需要根据具体情况选择合适的FWT实现方式。

“相关推荐”对你有帮助么?

非常没帮助

没帮助

一般

有帮助

非常有帮助

提交

偶耶XJX

CSDN认证博客专家

CSDN认证企业博客

码龄5年

暂无认证

233

原创

22万+

周排名

78万+

总排名

13万+

访问

等级

3002

积分

117

粉丝

197

获赞

143

评论

356

收藏

私信

关注

热门文章

浅谈*迭代加深*深度优先搜索

7300

浅谈矩阵加速算法

6278

浅谈微分求导+泰勒展开+生成函数

3699

[ZJOI2015] 幻想乡战略游戏——树链剖分

3608

浅谈快速沃尔什变换(FWT)&快速莫比乌斯变换(FMT)

3590

分类专栏

信息竞赛解题

195篇

竞赛经验总结

35篇

其他

5篇

最新评论

NOI2022 游记

monster LZL:

orz我也是NOIP省二,希望我也可以像你那样逆袭吧

[PKUSC2022]撸猫——Hall定理

C202207xiaofang:

先点赞,等实力足够再来学习。

平行四边形不等式优化详解

Turing Kick out:

引用「dp[i][x]+dp[x+1][j]+cost[i][j]+dp[i+1][y]+dp[y+1][」

这里,dp[y+1][j+1] > dp[y+1][j], 你在放缩的时候这样操作,好像逻辑上就没有道理了。

平行四边形不等式优化详解

Turing Kick out:

引用「如果上述的w函数同时满足区间包含单调性和四边形不等式性质,那么函数dp也满足四边形不等式性质」

w函数在哪里?你是指cost[i, j]函数吗?

NOI2022 游记

zkq.:

重看一遍,感觉卷爷说的太深刻了

您愿意向朋友推荐“博客详情页”吗?

强烈不推荐

不推荐

一般般

推荐

强烈推荐

提交

最新文章

CSP-S2022游记

NOI2022 游记

[NOI2017] 整数,蚯蚓排队,泳池

2022年100篇

2021年91篇

2020年14篇

2019年22篇

2018年9篇

目录

目录

分类专栏

信息竞赛解题

195篇

竞赛经验总结

35篇

其他

5篇

目录

评论

被折叠的  条评论

为什么被折叠?

到【灌水乐园】发言

查看更多评论

添加红包

祝福语

请填写红包祝福语或标题

红包数量

红包个数最小为10个

红包总金额

红包金额最低5元

余额支付

当前余额3.43元

前往充值 >

需支付:10.00元

取消

确定

下一步

知道了

成就一亿技术人!

领取后你会自动成为博主和红包主的粉丝

规则

hope_wisdom 发出的红包

实付元

使用余额支付

点击重新获取

扫码支付

钱包余额

0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值