我们以前常见的多项式乘法长这个亚子:
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∣iA[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∣iA[j]
F W T ( B ) [ i ] = ∑ j ∣ i B [ j ] FWT(B)[i]=\sum_{j|i}B[j] FWT(B)[i]=∑j∣iB[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∣iA[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<n;mid<<=1)//每次将两块大小为mid的块合并成一个大块
for(int block=mid<<1,j=0;j<n;j+=block)//枚举每个大块
for(int i=j;i<j+mid;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∣jA[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<n;mid<<=1)
for(int block=mid<<1,j=0;j<n;j+=block)
for(int i=j;i<j+mid;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,怕多了各位不看呀,下面这些看起来繁琐的东西其实逻辑很简单的,静心细看就好):
接下来就是求解的证明了,还是像上面那样大力展开(自己手(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−1y=0∑2n−1A[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−1y=0∑2n−1A[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−1y=0∑2n−1A[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−1y=0∑2n−1A[x]×B[y]×(−1)P(c(i&x))+P(c(i&y))=x=0∑2n−1y=0∑2n−1A[x]×B[y]×(−1)P(c(i&x))×(−1)P(c(i&y))=x=0∑2n−1A[x]×(−1)P(c(i&x))×y=0∑2n−1B[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<n;mid<<=1)
for(int block=mid<<1,j=0;j<n;j+=block)
for(int i=j;i<j+mid;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;
}
}
题目传送门
有一说一,我觉得我这个代码超级好看!(虽然有点不要脸qwq)
#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<n;mid<<=1)
for(int block=mid<<1,j=0;j<n;j+=block)
for(int i=j;i<j+mid;i++)
f[i+mid]=(f[i+mid]+f[i]*type+mod)%mod;
}
void FWT_and(ll *f,int type)
{
for(int mid=1;mid<n;mid<<=1)
for(int block=mid<<1,j=0;j<n;j+=block)
for(int i=j;i<j+mid;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<n;mid<<=1)
for(int block=mid<<1,j=0;j<n;j+=block)
for(int i=j;i<j+mid;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<n;i++)a[i]=A[i],b[i]=B[i];
FWT(a,1);FWT(b,1);
for(int i=0;i<n;i++)a[i]=a[i]*b[i]%mod;
FWT(a,-1);
for(int i=0;i<n;i++)printf("%lld ",a[i]);
printf("\n");
}
int main()
{
scanf("%d",&n);n=1<<n;
for(int i=0;i<n;i++)scanf("%lld",&A[i]),A[i]%=mod;
for(int i=0;i<n;i++)scanf("%lld",&B[i]),B[i]%=mod;
work(FWT_or);work(FWT_and);work(FWT_xor);
}