给定 (n) 和序列 (a_0,a_1,dots,a_{2^n-1}) 和 (b_0,b_1,dots,b_{2^n-1}),求序列 (c_0,c_1,dots,c_{2^n-1}) 满足
[c_i=left(sum_{j|k=i,j&k=0} a_jcdot b_k ight)mod 4 ]
数据范围:(a_i,b_iin[0,3]),(0le nle 21)。
看到 (j|k=i) 便知道要搞个 (or) 运算的 ( exttt{FWT}),但是如何使得同时满足条件 (j&k=0) 呢?
设 (bits(x)) 表示 (x) 在二进制下的位数。
考虑如下 (3) 个可以利用的因素:
-
(mod 4) 相当于在二进制下取两位。
-
同时满足 (j|k=i,j&k=0) 必有 (bits(j)+bits(k)=bits(i))。
-
如果满足 (j|k=i),且 (bits(i)) 一定,必有 (bits(j)+bits(k)ge bits(i))。
所以可以令 (f_i=a_icdot 4^{bits(i)},g_i=b_icdot 4^{bits(i)}),通过 ( exttt{FWT}) 得到 (ans_i=sum_{j|k=i}f_jcdot g_k),然后最后的答案 (c_i=left(frac{ans_i}{4^{bits(i)}} ight)mod 4)。
抽象地解释一下:
( exttt{[]}) 表示两个二进制位(为 (0)),( exttt{<>}) 表示其他(除了答案两位)位的值,是由 (c_i) 溢出两位或者由满足 (bits(j)+bits(k)>bits(i)) 的 (j,k) 变换得的值,可以抛弃。
(f_j:a_junderbrace{ exttt{[][]...[][]}}_{bits(j)'s exttt{[]}})
(g_k:b_kunderbrace{ exttt{[][]...[][]}}_{bits(k)'s exttt{[]}})
(ans_i: exttt{<><>...<><>}c_iunderbrace{ exttt{[][]...[][]}}_{bits(i)'s exttt{[]}})
小蒟蒻或许讲不清楚,但我就这个水平了。放代码吧,注意 (f_j,g_k) 开 ( exttt{long long})。
//Data
const int M=21,N=1<<M;
int n,m,bit[N+7];
int bits(int x){return (x==0)?0:bit[x]?bit[x]:(bit[x]=bits(x-(x&-x))+1);}
//FWT
void fwt(lng f[],int t){ //or fwt 模板
for(int mid=1;mid<n;mid<<=1)
for(int i=0;i<n;i+=mid<<1)
for(int j=i;j<mid+i;j++) f[mid+j]+=f[j]*t;
}
lng f[N+7],g[N+7],ans[N+7];
//Main
int main(){
n=1<<(m=ri);
for(int i=0,c;i<n;i++){
while(!isdigit(c=fr()));
f[i]=(15ll&c)<<(bits(i)<<1);
//这题是在 CF 上交的,有很多奇奇怪怪的错误,反正这里只能写 15ll&c,写 (lng)(c-'0') 都会挂
}
for(int i=0,c;i<n;i++){
while(!isdigit(c=fr()));
g[i]=(15ll&c)<<(bits(i)<<1);
}
fwt(f,1),fwt(g,1);
for(int i=0;i<n;i++) ans[i]=f[i]*g[i]; // CF 会显示这里挂了
fwt(ans,-1);
for(int i=0;i<n;i++) printf("%lld",(ans[i]>>(bits(i)<<1))&3);
putchar('
');
return 0;
}
萌新初学多项式,巨佬多多指教,觉得写得不清楚就在评论中随意 ( exttt{D})。祝大家学习愉快!