zoukankan      html  css  js  c++  java
  • 多项式板子(留坑待填)

    多项式

    • 形式化的,一个多项式 (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;
    }
    
  • 相关阅读:
    A1083. List Grades
    A1075. PAT Judge
    uva 10054 The Necklace 欧拉回路
    uva 1423 / Guess
    poj3164 最小树形图
    uva 11865 stream my contest 最小树形图 朱刘算法
    uva 1494
    获取android源码中遇到的问题
    MTK平台Android项目APK预置方案
    Android Lights
  • 原文地址:https://www.cnblogs.com/shawk/p/14218700.html
Copyright © 2011-2022 走看看