测试地址:Kanade’s Convolution
题目大意:给定两个长为
2m(m≤19)
2
m
(
m
≤
19
)
的向量
A,B
A
,
B
,计算向量
C
C
,其中:
做法:本题需要用到FWT。
看到这种类似卷积的东西,又是关于位运算,自然想到FWT。但是这个式子看上去实在复杂,三种位运算都有,貌似不可算,所以我们先化一下式子:
首先我们根据位运算的定义,有: (i and j)+(i xor j)=i or j ( i a n d j ) + ( i x o r j ) = i o r j 。于是我们把枚举 i,j i , j 改成枚举 x=i or j,y=i xor j x = i o r j , y = i x o r j ,那么条件 i and j=k i a n d j = k 就变成了 x−y=k x − y = k ,根据 x,y x , y 之间的特殊关系,减号可以换成 xor x o r 。在这种情况下,需要有一个约束条件使得存在一些与一对 x,y x , y 对应的 i,j i , j ,这个约束条件为 x and y=y x a n d y = y 。又根据一些二进制位的关系可以得出,一对这样的 x,y x , y 所对应的 i,j i , j 对数为 2bit(y) 2 b i t ( y ) ,其中 bit(y) b i t ( y ) 指 y y 的二进制位数。这样我们就把式子化成了下面的形式:
这时候这个式子已经很有卷积的感觉了,关键是方括号内的部分怎么处理。这时候我们需要把条件换成另一个等价的条件。当 x xor y=k x x o r y = k 时, x and y=y x a n d y = y 和 bit(x)−bit(y)=bit(k) b i t ( x ) − b i t ( y ) = b i t ( k ) 是等价的,证明还是从 x,y x , y 间的特殊关系着手。于是式子变成:
Ck=∑x xor y=k[bit(x)−bit(y)=bit(k)]⋅Bx⋅Ay⋅2bit(y)
C
k
=
∑
x
x
o
r
y
=
k
[
b
i
t
(
x
)
−
b
i
t
(
y
)
=
b
i
t
(
k
)
]
⋅
B
x
⋅
A
y
⋅
2
b
i
t
(
y
)
令向量 F(A,k)i=[bit(i)=k]⋅Ai F ( A , k ) i = [ b i t ( i ) = k ] ⋅ A i (实际上就是把 bit(i) b i t ( i ) 为 k k 的所有单独抽出来),再令 A′i=Ai⋅2bit(i) A i ′ = A i ⋅ 2 b i t ( i ) ,有:
F(C,k)=∑mi=kF(B,i)⋅F(A′,i−k) F ( C , k ) = ∑ i = k m F ( B , i ) ⋅ F ( A ′ , i − k )
根据FWT得出的点值表示的性质,这些东西可以通过FWT后,直接对位相加、乘来计算,最后再把这一大堆进行逆FWT即可。
注意到 Ck=F(C,bit(k))k C k = F ( C , b i t ( k ) ) k ,于是我们只需按照上面的方法计算出 F(C,i) F ( C , i ) 即可解决此题,时间复杂度为 O(m22m) O ( m 2 2 m ) 。
以下是本人代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const ll inv=(mod+1)>>1;
int m,n,bit[600010];
ll a[600010],b[600010];
ll A[20][600010]={0},B[20][600010]={0},C[20][600010]={0};
void FWT(ll *a,int n,int type)
{
for(int mid=1;mid<n;mid<<=1)
for(int l=0;l<n;l+=(mid<<1))
for(int k=0;k<mid;k++)
{
ll x=a[l+k],y=a[l+mid+k];
a[l+k]=(x+y)%mod;
a[l+mid+k]=(x-y+mod)%mod;
if (type==-1)
{
a[l+k]=a[l+k]*inv%mod;
a[l+mid+k]=a[l+mid+k]*inv%mod;
}
}
}
int main()
{
scanf("%d",&m);
n=(1<<m);
for(int i=0;i<n;i++)
scanf("%lld",&a[i]);
for(int i=0;i<n;i++)
scanf("%lld",&b[i]);
for(int i=0;i<n;i++)
{
bit[i]=0;
int x=i;
while(x)
{
if (x&1) bit[i]++;
x>>=1;
}
}
for(int i=0;i<n;i++)
{
A[bit[i]][i]=a[i]*(1ll<<bit[i])%mod;
B[bit[i]][i]=b[i];
}
for(int i=0;i<=m;i++)
FWT(A[i],n,1),FWT(B[i],n,1);
for(int i=0;i<=m;i++)
for(int j=0;j+i<=m;j++)
{
int k=j+i;
for(int p=0;p<n;p++)
C[i][p]=(C[i][p]+A[j][p]*B[k][p])%mod;
}
for(int i=0;i<=m;i++)
FWT(C[i],n,-1);
ll now=1,ans=0;
for(int i=0;i<n;i++)
{
ans=(ans+C[bit[i]][i]*now)%mod;
now=now*1526ll%mod;
}
printf("%lld\n",ans);
return 0;
}