多项式模板

constexpr int MOD = 998244353, INV_2 = (MOD + 1) / 2;
void inc(int &x, int y) {
  x += y;
  if (x >= MOD) x -= MOD;
}
void dec(int &x, int y) {
  x -= y;
  if (x < 0) x += MOD;
}
int add(int x, int y) {
  x += y;
  return x >= MOD ? x - MOD : x;
}
int sub(int x, int y) {
  x -= y;
  return x < 0 ? x + MOD : x;
}
int neg(int x) { return x ? MOD - x : 0; }
int adj(int x) { return x < 0 ? x + MOD : x; }
int qpow(int x, int y) {
  int ret = 1;
  for (; y; y >>= 1, x = (ll)x * x % MOD)
    if (y & 1) ret = (ll)ret * x % MOD;
  return ret;
}
namespace poly {
struct poly_t : vector<int> {
  using vector<int>::vector;
};
constexpr int MAXLOG = 18, MAXLEN = 1 << MAXLOG;
int coef[MAXLEN], rev[MAXLEN], inv[MAXLEN + 1];
void init() {
  inv[1] = 1;
  for (int i = 2; i <= MAXLEN; ++i)
    inv[i] = (ll)inv[MOD % i] * (MOD - MOD / i) % MOD;
  for (int i = 1; i < MAXLEN; ++i)
    rev[i] = rev[i >> 1] >> 1 | (i & 1 ? MAXLEN >> 1 : 0);
  int tmp = qpow(3, (MOD - 1) / MAXLEN);
  coef[MAXLEN / 2] = 1;
  for (int i = MAXLEN / 2 + 1; i < MAXLEN; ++i)
    coef[i] = (ll)coef[i - 1] * tmp % MOD;
  for (int i = MAXLEN / 2 - 1; i >= 1; --i) coef[i] = coef[i << 1];
}
void ntt(poly_t &f, int v) {
  int len = f.size(), d = __lg(len);
  for (int i = 1; i < len; ++i) {
    int tmp = rev[i] >> (MAXLOG - d);
    if (i < tmp) swap(f[i], f[tmp]);
  }
  for (int i = 1; i < len; i <<= 1) {
    for (int j = 0; j < len; j += i << 1) {
      for (int k = j; k < j + i; ++k) {
        int tmp = (ll)f[k + i] * coef[i + k - j] % MOD;
        f[k + i] = sub(f[k], tmp);
        inc(f[k], tmp);
      }
    }
  }
  if (v == -1) {
    int tmp = inv[len];
    for (auto &i : f) i = (ll)i * tmp % MOD;
    reverse(f.begin() + 1, f.end());
  }
}
poly_t &operator+=(poly_t &f, const poly_t &g) {
  if (g.size() > f.size()) f.resize(g.size());
  for (int i = 0; i < (int)g.size(); ++i) inc(f[i], g[i]);
  return f;
}
poly_t &operator-=(poly_t &f, const poly_t &g) {
  if (g.size() > f.size()) f.resize(g.size());
  for (int i = 0; i < (int)g.size(); ++i) dec(f[i], g[i]);
  return f;
}
poly_t &operator*=(poly_t &f, poly_t g) {
  if (f.empty() || g.empty()) return f = {};
  int tar = f.size() + g.size() - 1, len = (tar == 1 ? 1 : 2 << __lg(tar - 1));
  f.resize(len);
  g.resize(len);
  ntt(f, 1);
  ntt(g, 1);
  for (int i = 0; i < len; ++i) f[i] = (ll)f[i] * g[i] % MOD;
  ntt(f, -1);
  f.resize(tar);
  return f;
}
poly_t operator+(poly_t f, const poly_t &g) { return f += g; }
poly_t operator-(poly_t f, const poly_t &g) { return f -= g; }
poly_t operator*(poly_t f, const poly_t &g) { return f *= g; }
poly_t inver(const poly_t &f) {
  assert(!f.empty() && f[0]);
  poly_t ret(f.size());
  ret[0] = qpow(f[0], MOD - 2);
  for (int i = 1; i < (int)f.size(); i <<= 1) {
    poly_t g(i * 2), h(i * 2);
    copy(f.begin(), min(f.begin() + i * 2, f.end()), g.begin());
    copy(ret.begin(), ret.begin() + i, h.begin());
    ntt(g, 1);
    ntt(h, 1);
    for (int j = 0; j < i * 2; ++j) g[j] = (ll)g[j] * h[j] % MOD;
    ntt(g, -1);
    fill(g.begin(), g.begin() + i, 0);
    ntt(g, 1);
    for (int j = 0; j < i * 2; ++j) g[j] = (ll)g[j] * h[j] % MOD;
    ntt(g, -1);
    for (int j = i, up = min(i * 2, (int)f.size()); j < up; ++j)
      ret[j] = neg(g[j]);
  }
  return ret;
}
poly_t deriv(const poly_t &f) {
  if (f.empty()) return {};
  poly_t ret(f.size() - 1);
  for (int i = 0; i < (int)ret.size(); ++i)
    ret[i] = (ll)f[i + 1] * (i + 1) % MOD;
  return ret;
}
poly_t integ(const poly_t &f) {
  if (f.empty()) return {};
  poly_t ret(f.size() + 1);
  for (int i = 1; i <= (int)f.size(); ++i) ret[i] = (ll)f[i - 1] * inv[i] % MOD;
  return ret;
}
poly_t ln(const poly_t &f) {
  assert(!f.empty() && f[0] == 1);
  poly_t ret = integ(deriv(f) * inver(f));
  ret.resize(f.size());
  return ret;
}
poly_t exp(const poly_t &f) {
  if (f.empty()) return {1};
  assert(!f[0]);
  poly_t ret(f.size());
  ret[0] = 1;
  for (int i = 1; i < (int)f.size(); i <<= 1) {
    poly_t g(i * 2), h(i * 2);
    copy(ret.begin(), ret.begin() + i, g.begin());
    copy(f.begin(), min(f.begin() + i * 2, f.end()), h.begin());
    h -= ln(g);
    inc(h[0], 1);
    ntt(g, 1);
    ntt(h, 1);
    for (int j = 0; j < i * 2; ++j) g[j] = (ll)g[j] * h[j] % MOD;
    ntt(g, -1);
    copy(g.begin() + i, g.begin() + min(i * 2, (int)f.size()), ret.begin() + i);
  }
  ret.resize(f.size());
  return ret;
}
poly_t sqrt(const poly_t &f) {
  assert(!f.empty() && f[0] == 1);
  poly_t ret = {1};
  for (int i = 1; i < (int)f.size(); i <<= 1) {
    poly_t g(i * 2);
    copy(f.begin(), min(f.begin() + i * 2, f.end()), g.begin());
    ret.resize(i * 2);
    ret += g * inver(ret);
    ret.resize(i * 2);
    for (auto &j : ret) j = (ll)j * INV_2 % MOD;
  }
  ret.resize(f.size());
  return ret;
}
poly_t pow(poly_t f, int k) {
  assert(!f.empty() && f[0] == 1);
  f = ln(f);
  for (auto &i : f) i = (ll)i * k % MOD;
  return exp(f);
}
}  // namespace poly
using poly::poly_t;
posted @ 2024-03-28 07:49  JCY_std  阅读(31)  评论(0编辑  收藏  举报