【模板】多项式乘法(单模数 dit-dif 优化)& 差卷积

【模板】多项式乘法(单模数 dit-dif 优化)& 差卷积

需要支持多模数的就是 github 上那一个 template-poly,那个还额外加了一些判断合法性的东西。单模数而且不要求很精细的就这个。

差卷积:ck=i=0aibk+i 是一个很常用的一个卷积形式,做法是 reverse 整个 a 后直接将 ab 卷起来然后去掉前 a.size() - 1 项,剩下的后导零根据实际情况处理。

单位根:m2 的次幂,现在处理 m2m1

mint wn = qpow(mint(3), (mint::mod - 1) / m >> 2);
for (int i = m; i < m << 1; i++) w[i] = wn * w[i ^ m];

dif 是系数到蝴蝶变换后的点值,len 从大往小:

auto x = a[i + j], y = a[i + j + k] * w[t];
a[i + j] = x + y, a[i + j + k] = x - y;

dit 是蝴蝶变换后的点值到系数,len 从小往大:

auto x = a[i + j], y = a[i + j + k];
a[i + j] = x + y, a[i + j + k] = (x - y) * w[t];

然后 reverse(a.begin() + 1, a.end()) 并除以 n

int glim(size_t x) { return x == 1 ? 1 : 2 << __lg(x - 1); }
using poly = vector<mint>;
vector<mint> wt;
vector<mint>& ntt_init(int n) {
  auto &w = wt;
  if (w.empty()) w = {1};
  while ((int)w.size() < n) {
    int m = (int)w.size();
    mint wn = qpow(mint(3), (mint::mod - 1) / m >> 2);
    w.resize(m << 1);
    for (int i = m; i < m << 1; i++) w[i] = wn * w[i ^ m];
  }
  return w;
}
valarray<mint> dif(const poly& src, int n) {
  auto &w = ntt_init(n);
  valarray<mint> a(mint(0), n);
  copy(src.begin(), src.end(), &a[0]);
  for (int len = n, k = n >> 1; k >= 1; len >>= 1, k >>= 1) {
    for (int i = 0, t = 0; i < n; i += len, t++) {
      for (int j = 0; j < k; j++) {
        auto x = a[i + j], y = a[i + j + k] * w[t];
        a[i + j] = x + y, a[i + j + k] = x - y;
      }
    }
  }
  return a;
}
poly dit(const valarray<mint>& src) {
  int n = (int)src.size();
  auto &w = ntt_init(n);
  poly a(begin(src), end(src));
  for (int k = 1, len = 2; len <= n; k <<= 1, len <<= 1) {
    for (int i = 0, t = 0; i < n; i += len, t++) {
      for (int j = 0; j < k; j++) {
        auto x = a[i + j], y = a[i + j + k];
        a[i + j] = x + y, a[i + j + k] = (x - y) * w[t];
      }
    }
  }
  mint iv = mint::mod - (mint::mod - 1) / n;
  for (int i = 0; i < n; i++) a[i] *= iv;
  reverse(a.begin() + 1, a.end());
  return a;
}
poly diff_conv(poly a, poly b) {
  reverse(a.begin(), a.end());
  int len = glim(a.size() + b.size() - 1);
  auto c = dit(dif(a, len) * dif(b, len));
  c.erase(c.begin(), c.begin() + a.size() - 1);
  c.resize(b.size() - a.size() + 1);
  return c;
}
posted @   caijianhong  阅读(34)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示