• 多项式操作公式记录


    多项式操作公式记录

    不证明了。

    以下默认 (A(x))((n - 1)) 次多项式 (A(x) = sum_{i = 0}^{n - 1} a_i x^i),且 (n)(2) 的整数幂。

    快速傅里叶变换/数论变换

    [A_(omega_n^k)~=~A_0(omega_m^k) + omega_n^kA_1(omega_m^k) ]

    [A(omega_n^{k + m})~=~A_0(omega_m^k) - omega_n^kA_1(omega_m^k) ]

    其中 (m = frac{n - 1}{2})(A_0(x) = sum_{i = 0}^m a_{2i} x^i)(A_1(x) = sum_{i = 0}^m a^{2i + 1}x^i)(omega_n) 代表最小的 (n) 次单位根/原根。

    求乘法逆

    (A(x) B(x) equiv 1 pmod {x^n})

    [B_{2k}(x) equiv 2 B_{k}(x) - A_{2k}(x) imes B_{k}^{2}(x) pmod {x^{2k}} ]

    其中 (A_k(x)) 代表 (A) 的前 (k) 项;(B_k(x)~=~A_k^{-1}(x))

    注意:(B_k(x)) 不一定是 (A_n(x)) 乘法逆的前 (k) 项,它只是 (A_n(x))(k) 项的乘法逆。

    求对数函数

    [B(x) = ln A(x) ]

    [B'(x)~equiv~A'(x) A^{-1}(x) pmod {x^n} ]

    [B(x)~=~int B'(x) ext{d}x ]

    求导、积分公式:

    [f(x) = Cx^a~~Rightarrow~~ f'(x) = C(a - 1)x^{a - 1} ]

    [f(x) = Cx^a~~ ~~Rightarrow~~ int f(x) ext{d}x = frac{C}{a + 1} x^{a + 1} ]

    其中 (C) 是常数。对于多项式,二者均是线性可加的。

    求指数函数

    [B(x) = e^{A(x)} ]

    有递推式

    [B_{2k}(x)~=~B_k(x) imes(1 - ln B_k(x) + A_{2k}(x)) ]

    其中下标代表多项式的前几项。

    递归求解即可。

    多项式 (k) 次幂

    [B(x) equiv (A(x))^k pmod {x^n} ]

    (B(x) = exp (k ln A(x)))

    多项式开根

    即多项式 (2^{-1}) 次幂。

    封装代码

    namespace Poly {
    
    const int G = 3;
    const int MOD = 998244353;
    const int PHI = 998244352;
    const int DPHI = 998244351;
    const int SzI = sizeof(int);
    const int SzL = sizeof(long long int);
    
    void Init(int *const A, const int N) {
      for (int i = 0; i < N; ++i) {
        qr(A[i]);
      }
    }
    
    void Print(const int *const A, const int N) {
      int DN = N - 1;
      for (int i = 0; i < DN; ++i) {
        qw(A[i], ' ', true);
      }
      qw(A[DN], '
    ', true);
    }
    
    void GetN(int n, int &N) {
      N = 1;
      while (N < n) N <<= 1;
    }
    
    int mpow(int x, int y) {
      int _ret = 1;
      while (y) {
        if (y & 1)  _ret = 1ll * x * _ret % MOD;
        x = 1ll * x * x % MOD;
        y >>= 1;
      }
      return _ret;
    }
    
    int tax[maxn], taxlen;
    
    void GetRev(const int N) {
      int p = 1, d = N >> 1;
      for (int w = p; w < N; w = p) {
        for (int i = 0; i < w; ++i) {
          tax[p++] = tax[i] | d;
        }
        d >>= 1;
      }
      taxlen = N;
    }
    
    void MakeRev(int *const A, const int N) {
      for (int i = 1; i < N; ++i) if (tax[i] > i) {
        std::swap(A[i], A[tax[i]]);
      }
    }
    
    void Modint(int &x) {
      while (x >= MOD) x -= MOD;
      while (x < 0) x += MOD;
    }
    
    void NTT(int *const A, const int N) {
      if (taxlen != N) {
        GetRev(N);
      }
      MakeRev(A, N);
      for (int w = 2, M = 1; w <= N; w <<= 1) {
        int Wn = mpow(G, PHI / w);
        for (int L = 0; L < N; L += w) {
          ll g = 1;
          for (int i = L, lm = L + M, j = lm; i < lm; ++i, ++j) {
            ll x = A[i], y = A[j];
            A[i] = (x + g * y) % MOD; A[j] = (x - g * y) % MOD;
            (g *= Wn) %= MOD;
          }
        }
        M = w;
      }
      for (int i = 0; i < N; ++i) {
        Modint(A[i]);
      }
    }
    
    void GetInv(const int *const A, int *const B, const int N) {
      static int C[maxn];
      B[0] = mpow(A[0], DPHI);
      for (int w = 2, M = 4; w <= N; M <<= 1) {
        memcpy(C, A, w * SzI);
        NTT(B, M); NTT(C, M);
        for (int i = 0; i < M; ++i) {
          B[i] = (B[i] << 1) % MOD - 1ll * C[i] * B[i] % MOD * B[i] % MOD;
          Modint(B[i]);
        }
        NTT(B, M);
        std::reverse(B + 1, B + M);
        for (int i = 0, iv = mpow(M, DPHI); i < w; ++i) {
          B[i] = 1ll * B[i] * iv % MOD;
        }
        memset(B + w, 0, w * SzI);
        w = M;
      }
      memset(C, 0, (N << 1) * SzI);
    }
    
    void GetDer(const int *const A, int *const B, const int N) {
      for (int i = 1; i < N; ++i) {
        B[i - 1] = 1ll * A[i] * i % MOD;
      }
      B[N - 1] = 0;
    }
    
    void GetInte(const int *const A, int *const B, const int N) {
      B[0] = 0;
      for (int i = 1; i < N; ++i) {
        B[i] = 1ll * A[i - 1] * mpow(i, DPHI) % MOD;
      }
    }
    
    void GetLn(const int *const A, int *const B, const int N) {
      static int C[maxn];
      GetDer(A, B, N);
      GetInv(A, C, N);
      int M = N << 1;
      NTT(B, M); NTT(C, M);
      for (int i = 0; i < M; ++i) {
        C[i] = 1ll * B[i] * C[i] % MOD;
      }
      NTT(C, M);
      std::reverse(C + 1, C + M);
      for (int i = 0, iv = mpow(M, DPHI); i < N; ++i) {
        C[i] = 1ll * C[i] * iv % MOD;
      }
      GetInte(C, B, N);
      memset(B + N, 0, N * SzI);
      memset(C, 0, M * SzI);
    }
    
    void GetExp(const int *const A, int *const B, const int N) {
      static int C[maxn];
      if (N == 1) {
        B[0] = 1;
        return;
      }
      GetExp(A, B, N >> 1);
      GetLn(B, C, N);
      int M = N << 1;
      for (int i = 0; i < N; ++i) {
        C[i] = -C[i] + A[i];
        Modint(C[i]);
      }
      C[0] += 1;
      NTT(C, M); NTT(B, M);
      for (int i = 0; i < M; ++i) {
        B[i] = 1ll * B[i] * C[i] % MOD;
      }
      NTT(B, M);
      std::reverse(B + 1, B + M);
      for (int i = 0, iv = mpow(M, DPHI); i < N; ++i) {
        B[i] = 1ll * B[i] * iv % MOD;
      }
      memset(B + N, 0, N * SzI);
      memset(C, 0, M * SzI);
    }
    
    void GetPow(const int *const A, const int k, int *const B, const int N) {
      static int C[maxn];
      GetLn(A, C, N);
      for (int i = 0; i < N; ++i) {
        C[i] = 1ll * C[i] * k % MOD;
      }
      GetExp(C, B, N);
      memset(C, 0, N * SzI);
    }
    
    }
    
  • 相关阅读:
    上拉电阻与下拉电阻的总结
    硬件设计中的30个错误想法与原因分析
    转载:个人电子技术经验积累
    最为精辟和实用的按键处理程序
    TM1637驱动程序
    17.TLB
    14.PTD与的基址
    java读写文件及保留指定位小数
    Java堆内存不足
    Ubuntu下创建程序启动器
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/12157488.html
Copyright © 2020-2023  润新知