• 多项式板子(留坑待填)


    多项式

    • 形式化的,一个多项式 (f(x)) 可以表示为

    [f(x)=sum _ia_ix^i ]


    多项式加减法

    • 直接对应系数相加减

    多项式乘法

    • 可以解决形如 (Q_j=sum_{i=0}^{j}f_ig_{j-i}) 的卷积

    快速傅里叶变换(FFT)

    • 前置知识:离散傅里叶变换(DFT)、复数、单位根

    • 用DFT将系数表达式转换为点值表达式,运算后再用IDFT转换为系数表达式

    Show Code
    #include <cmath>
    #include <cstdio>
    #define swap(x, y) ({Complex xx = x; x = y; y = xx;})
    #define Mul(x, y) ((Complex) {x.r * y.r - x.i * y.i, x.r * y.i + x.i * y.r})
    
    const double pi = acos(-1);
    const int N = (1 << 18) + 5;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar())
            if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar())
            x = x * 10 + c - '0';
        return x * f;
    }
    
    struct Complex {
        double r, i;
    }a[N], b[N];
    int n, m, l, k, r[N];
    
    void FFT(Complex *a, int k) {
        for (int i = 0; i <= l; ++i)
            if (i < r[i]) swap(a[i], a[r[i]]);
        for (int d = 1; d < l; d *= 2) {
            int d2 = d * 2;
            Complex W = (Complex) {cos(pi / d), sin(pi / d) * k};
            for (int i = 0; i < l; i += d2) {
                Complex w = (Complex) {1, 0};
                for (int j = i; j < i + d; ++j, w = Mul(w, W)) {
                    Complex x = a[j], y = Mul(a[j+d], w);
                    a[j] = (Complex) {x.r + y.r, x.i + y.i};
                    a[j+d] = (Complex) {x.r - y.r, x.i - y.i};
                }
            }
        }
    }
    
    int main() {
        n = read(); m = read();
        for (int i = 0; i <= n; ++i)
            a[i].r = read();
        for (int i = 0; i <= m; ++i)
            b[i].r = read();
        for (l = 1; l <= n + m; l *= 2, ++k); --k;
        for (int i = 0; i < l; ++i)
            r[i] = (r[i>>1] >> 1) | ((i & 1) << k);
        FFT(a, 1); FFT(b, 1);
        for (int i = 0; i < l; ++i)
            a[i] = Mul(a[i], b[i]);
        FFT(a, -1);
        for (int i = 0; i <= n + m; ++i)
            printf("%d ", (int)(a[i].r / l + 0.5));
        return 0;
    }
    

    快速数论变换(NTT) (最新)

    • NTT可以解决有模数的问题,结果更加准确,用原根替代单位根,预处理单位根会快很多
    Show Code
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    const int N = 1 << 18 | 5, M = 998244353;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar())
            if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar())
            x = x * 10 + c - '0';
        return x * f;
    }
    
    int n, m, a[N], b[N], r[N], w[N], l, k;
    
    int Pow(int a, int k, int ans = 1) {
        for (; k; k >>= 1, a = 1ll * a * a % M)
            if (k & 1) ans = 1ll * ans * a % M;
        return ans;
    }
    
    void NTT(int *a, bool g = 1) {
        for (int i = 0; i < l; ++i) 
            if (i < r[i]) std::swap(a[i], a[r[i]]);
        for (int m = 1, d = 2; m < l; m *= 2, d *= 2) {
            for (int i = 0; i < l; i += d) {
                for (int j = i; j < i + m; ++j) {
                    int x = a[j], y = 1ll * a[j+m] * w[m+j-i] % M;
                    if ((a[j] = x + y) >= M) a[j] -= M;
                    if ((a[j+m] = x - y) < 0) a[j+m] += M;
                }
            }
        }
        if (!g) std::reverse(a + 1, a + l);
    }
    
    int main() {
        n = read(); m = read();
        for (int i = 0; i <= n; ++i) a[i] = read();
        for (int i = 0; i <= m; ++i) b[i] = read();
        for (l = 1; l < n + m; l *= 2); k = l >> 1;
        w[k] = 1; w[k+1] = Pow(3, (M - 1) / l);
        for (int i = k + 2; i < l; ++i) w[i] = 1ll * w[i-1] * w[k+1] % M;
        for (int i = k - 1; i >= 0; --i) w[i] = w[i*2];
        for (int i = 0; i < l; ++i) r[i] = (r[i>>1] >> 1) | (i & 1 ? k : 0);
        NTT(a); NTT(b);
        for (int i = 0; i < l; ++i) a[i] = 1ll * a[i] * b[i] % M;
        NTT(a, 0);
        int inv = Pow(l, M - 2);
        for (int i = 0; i <= n + m; ++i) printf("%lld ", 1ll * a[i] * inv % M);
        return 0;
    }
    

    快速沃尔什变换(FWT)

    [C_i=sum _{i=jigoplus k}A_iB_j ]

    • 有的卷积形式中 (igoplus) 可能不是+,而是位运算,这就需要FWT了
    Show Code
    #include <cstdio>
    #include <cstring>
    
    const int N = 1 << 17 | 5, M = 998244353, inv2 = 499122177;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar())
            if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar())
            x = x * 10 + c - '0';
        return x * f;
    }
    
    int n, A[N], B[N], a[N], b[N];
    
    void FWT(int *a, int od, bool g = 0) {
        for (int d = 1; d < n; d *= 2) {
            for (int i = 0, d2 = d * 2; i < n; i += d2) {
                for (int j = i; j < i + d; ++j) {
                    if (od == 1) {// or 或 |
                        if (!g && (a[j+d] += a[j]) >= M) a[j+d] -= M;
                        else if (g && (a[j+d] -= a[j]) < 0) a[j+d] += M;
                    }
                    else if (od == 2) {// ans 与 &
                        if (!g && (a[j] += a[j+d]) >= M) a[j] -= M;
                        else if (g && (a[j] -= a[j+d]) < 0) a[j] += M;
                    }
                    else { // xor 异或 ^
                        int x = a[j], y = a[j+d];
                        if ((a[j] = x + y) >= M) a[j] -= M;
                        if ((a[j+d] = x - y) < 0) a[j+d] += M;
                        if (g) a[j] = 1ll * a[j] * inv2 % M, a[j+d] = 1ll * a[j+d] * inv2 % M;
                    }
                }
            }
        }
    }
    
    void Solve(int k) {
        memcpy(a, A, n * 4);
        memcpy(b, B, n * 4);
        FWT(a, k); FWT(b, k);
        for (int i = 0; i < n; ++i)
            a[i] = 1ll * a[i] * b[i] % M;
        FWT(a, k, 1);
        for (int i = 0; i < n; ++i)
            printf("%d ", a[i]);
        puts("");
    }
    
    int main() {
        n = 1 << read();
        for (int i = 0; i < n; ++i)
            A[i] = read();
        for (int i = 0; i < n; ++i)
            B[i] = read();
        Solve(1); Solve(2); Solve(3);
        return 0;
    }
    
  • 相关阅读:
    Android OpenGL ES 2.0 (四) 灯光perfragment lighting
    Android OpenGL ES 2.0 (五) 添加材质
    冒泡排序函数
    javascript object 转换为 json格式 toJSONString
    Liunx CentOS 下载地址
    jquery 图片切换特效 鼠标点击左右按钮焦点图切换滚动
    javascript 解析csv 的function
    mysql Innodb Shutdown completed; log sequence number解决办法
    Centos 添加 yum
    javascript 键值转换
  • 原文地址:https://www.cnblogs.com/shawk/p/14218700.html
Copyright © 2020-2023  润新知