• FWT


    快速沃尔什变换

    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 #include <bits/stdc++.h>
     2 
     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 }
    洛谷P4717 快速沃尔什变换
  • 相关阅读:
    [COCI20142015#1] Kamp
    [CEOI2007]树的匹配Treasury
    [JLOI2016/SHOI2016]侦察守卫
    [POI2015]MOD
    [BJOI2017]机动训练
    [九省联考2018]一双木棋chess
    [清华集训2012]串珠子
    [POI2014]ZALFreight
    [SHOI2009]舞会
    [COCI2019]Mobitel
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10513402.html
Copyright © 2020-2023  润新知