快速沃尔什变换
fengwentao
解决集合卷积。说人话就是把FFT下标的+变成位运算。
&和|的FWT可以用高维前缀和来理解。
考虑对于A | B = C,我们有A'i = ∑Aj,其中j⊂i。B同理。
接下来我们把A'和B'对位相乘得C'。显然有C'i = ∑Cj,其中j⊂i。
接下来把C逆变换回去即可。
考虑怎么求A'。
我们先求一次A0,A0i表示二进制第0位是i的子集,0位以上都是严格等于i的位置权值和。
然后求A1,A1i表示二进制0,1位都是i的子集,而1位以上严格等于i的位置权值和。
然后搞完最高位就完事了。逆变换就反着来。
异或是什么毒瘤?见鬼去吧!
核心片段背诵:
|:(0, 1) -> (0, 0 + 1) 逆:(0, 1) -> (0, 0 - 1)
&:(0, 1) -> (0 + 1, 1) (0, 1) -> (0 - 1, 1)
^:(0, 1) -> (0 + 1, 0 - 1) (0, 1) -> ((0 + 1) / 2, (0 - 1) / 2)
写法跟FFT差不多,尤其是xor...
首先是裸到爆炸的模板题...
1 #include2 3 const int N = 140010, MO = 998244353, inv2 = 499122177; 4 5 int a[N], b[N], c[N]; 6 7 inline void FWT_or(int *a, int n, int f) { 8 for(int len = 1; len < n; len <<= 1) { 9 for(int i = 0; i < n; i += (len << 1)) {10 for(int j = 0; j < len; j++) {11 a[i + len + j] = (a[i + len + j] + f * a[i + j]) % MO;12 }13 }14 }15 return;16 }17 18 inline void FWT_and(int *a, int n, int f) {19 for(int len = 1; len < n; len <<= 1) {20 for(int i = 0; i < n; i += (len << 1)) {21 for(int j = 0; j < len; j++) {22 a[i + j] = (a[i + j] + f * a[i + len + j]) % MO;23 }24 }25 }26 return;27 }28 29 inline void FWT_xor(int *a, int n, int f) {30 for(int len = 1; len < n; len <<= 1) {31 for(int i = 0; i < n; i += (len << 1)) {32 for(int j = 0; j < len; j++) {33 int t = a[i + len + j];34 a[i + len + j] = (a[i + j] - t) % MO;35 a[i + j] = (a[i + j] + t) % MO;36 if(f == -1) {37 a[i + j] = 1ll * a[i + j] * inv2 % MO;38 a[i + len + j] = 1ll * a[i + len + j] * inv2 % MO;39 }40 }41 }42 }43 return;44 }45 46 int main() {47 48 int lm, n;49 scanf("%d", &lm);50 n = 1 << lm;51 for(int i = 0; i < n; i++) {52 scanf("%d", &a[i]);53 }54 for(int i = 0; i < n; i++) {55 scanf("%d", &b[i]);56 }57 58 FWT_or(a, n, 1); FWT_or(b, n, 1);59 for(int i = 0; i < n; i++) c[i] = 1ll * a[i] * b[i] % MO;60 FWT_or(a, n, -1); FWT_or(b, n, -1); FWT_or(c, n, -1);61 for(int i = 0; i < n; i++) {62 printf("%d ", (c[i] + MO) % MO);63 }64 puts("");65 66 FWT_and(a, n, 1); FWT_and(b, n, 1);67 for(int i = 0; i < n; i++) c[i] = 1ll * a[i] * b[i] % MO;68 FWT_and(a, n, -1); FWT_and(b, n, -1); FWT_and(c, n, -1);69 for(int i = 0; i < n; i++) {70 printf("%d ", (c[i] + MO) % MO);71 }72 puts("");73 74 FWT_xor(a, n, 1); FWT_xor(b, n, 1);75 for(int i = 0; i < n; i++) c[i] = 1ll * a[i] * b[i] % MO;76 FWT_xor(a, n, -1); FWT_xor(b, n, -1); FWT_xor(c, n, -1);77 for(int i = 0; i < n; i++) {78 printf("%d ", (c[i] + MO) % MO);79 }80 puts("");81 82 return 0;83 }