多项式操作公式记录

多项式操作公式记录

不证明了。

以下默认 A(x)(n1) 次多项式 A(x)=i=0n1aixi,且 n2 的整数幂。

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

A(ωnk) = A0(ωmk)+ωnkA1(ωmk)

A(ωnk+m) = A0(ωmk)ωnkA1(ωmk)

其中 m=n12A0(x)=i=0ma2ixiA1(x)=i=0ma2i+1xiωn 代表最小的 n 次单位根/原根。

求乘法逆

A(x)B(x)1(modxn)

B2k(x)2Bk(x)A2k(x)×Bk2(x)(modx2k)

其中 Ak(x) 代表 A 的前 k 项;Bk(x) = Ak1(x)

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

求对数函数

B(x)=lnA(x)

B(x)  A(x)A1(x)(modxn)

B(x) = B(x)dx

求导、积分公式:

f(x)=Cxa    f(x)=C(a1)xa1

f(x)=Cxa      f(x)dx=Ca+1xa+1

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

求指数函数

B(x)=eA(x)

有递推式

B2k(x) = Bk(x)×(1lnBk(x)+A2k(x))

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

递归求解即可。

多项式 k 次幂

B(x)(A(x))k(modxn)

B(x)=exp(klnA(x))

多项式开根

即多项式 21 次幂。

封装代码

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], '\n', 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);
}

}
posted @   一扶苏一  阅读(507)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
历史上的今天:
2019-01-06 【DP】【CF1097D】 Makoto and a Blackboard
点击右上角即可分享
微信分享提示