Problem p02539 (C++) — buggy submission, verdict: Runtime Error

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int maxn = 200000 + 10;
ll fac[maxn], inv[maxn], facinv[maxn], bin[maxn];
ll powMod(ll x, ll k) {
  ll ret = 1;
  while (k) {
    if (k & 1)
      ret = ret * x % mod;
    x = x * x % mod;
    k >>= 1;
  }
  return ret;
}
ll getinv(ll x) { return powMod(x, mod - 2); }
void pre() {
  fac[0] = 1;
  for (int i = 1; i < maxn; ++i)
    fac[i] = fac[i - 1] * i % mod;
  inv[1] = 1;
  for (int i = 2; i < maxn; ++i)
    inv[i] = (mod - mod / i) * inv[mod % i] % mod;
  facinv[0] = 1;
  for (int i = 1; i < maxn; ++i)
    facinv[i] = facinv[i - 1] * inv[i] % mod;
  bin[0] = 1;
  for (int i = 1; i < maxn; ++i)
    bin[i] = bin[i - 1] * 2 % mod;
}
ll C(int n, int m) {
  return n < m ? 0 : fac[n] * facinv[m] % mod * facinv[n - m] % mod;
}
int h[maxn], cnt[maxn];
int n, m, tot;

typedef vector<ll> poly;

namespace Poly {
const int L = 1 << 20;
const ll P = mod;

int lim, pos[L];

inline void deb(poly c) {
  for (int i = 0; i < (int)c.size(); i++)
    printf("%lld%c", c[i], " \\n"[i == (int)c.size() - 1]);
}

inline ll fpow(ll x, ll y) {
  ll res = 1;
  for (; y > 0; y >>= 1) {
    if (y & 1)
      res = res * x % P;
    x = x * x % P;
  }
  return res;
}

const ll inv2 = fpow(2, P - 2);

template <typename T> inline void inc(T &x, T y) {
  x += y;
  if (x >= P)
    x -= P;
}

template <typename T> inline void sub(T &x, T y) {
  x -= y;
  if (x < 0)
    x += P;
}

inline void prework(int len) {
  int l = 0;
  for (lim = 1; lim < len; lim <<= 1, ++l)
    ;
  for (int i = 0; i < lim; i++)
    pos[i] = (pos[i >> 1] >> 1) | ((i & 1) << (l - 1));
}

inline void ntt(poly &c, int opt) {
  c.resize(lim, 0);
  for (int i = 0; i < lim; i++)
    if (i < pos[i])
      swap(c[i], c[pos[i]]);
  for (int i = 1; i < lim; i <<= 1) {
    ll wn = fpow(5, (P - 1) / (i << 1));
    if (opt == -1)
      wn = fpow(wn, P - 2);
    for (int len = i << 1, j = 0; j < lim; j += len) {
      ll w = 1;
      for (int k = 0; k < i; k++, w = w * wn % P) {
        ll x = c[j + k], y = w * c[j + k + i] % P;
        c[j + k] = (x + y) % P, c[j + k + i] = (x - y + P) % P;
      }
    }
  }

  if (opt == -1) {
    ll inv = fpow(lim, P - 2);
    for (int i = 0; i < lim; i++)
      c[i] = c[i] * inv % P;
  }
}

inline poly operator*(const poly &x, const poly &y) {
  poly res, u = x, v = y;
  prework(u.size() + v.size() - 1);
  ntt(u, 1), ntt(v, 1);
  for (int i = 0; i < lim; i++)
    res.push_back(v[i] * u[i] % P);
  ntt(res, -1);
  res.resize(u.size() + v.size() - 1);
  for (; !res.empty() && !res[res.size() - 1]; res.pop_back())
    ;
  return res;
}

poly mul(const poly &x, const poly &y) { return x * y; }

poly getInv(poly x, int len) {
  x.resize(len);
  if (len == 1) {
    poly res;
    res.push_back(fpow(x[0], P - 2));
    return res;
  }
  poly y = getInv(x, (len + 1) >> 1);
  prework(len << 1);

  poly u = x, v = y, res;
  ntt(u, 1), ntt(v, 1);
  for (int i = 0; i < lim; i++)
    res.push_back(v[i] * (2LL - u[i] * v[i] % P + P) % P);
  ntt(res, -1);

  res.resize(len);
  return res;
}

inline void direv(poly &c) {
  for (int i = 0; i < (int)c.size() - 1; i++)
    c[i] = c[i + 1] * (i + 1) % P;
  c[c.size() - 1] = 0;
}

inline void integ(poly &c) {
  for (int i = (int)c.size() - 1; i > 0; i--)
    c[i] = c[i - 1] * fpow(i, P - 2) % P;
  c[0] = 0;
}

inline poly getLn(poly c) {
  poly a = getInv(c, (int)c.size());
  poly b = c;
  direv(b);

  poly res = b * a;
  res.resize(c.size());
  integ(res);
  return res;
}

poly getSqrt(poly x, int len) {
  x.resize(len);
  if (len == 1) {
    poly res;
    res.push_back(sqrt(x[0]));
    return res;
  }
  poly y = getSqrt(x, (len + 1) >> 1);
  poly u = x, v = y, w, res;
  w = getInv(y, len);

  prework(len << 1);
  ntt(u, 1), ntt(v, 1), ntt(w, 1);
  for (int i = 0; i < lim; i++)
    res.push_back((v[i] * v[i] % P + u[i]) % P * w[i] % P * inv2 % P);
  ntt(res, -1);
  res.resize(len);

  return res;
}

poly getExp(poly x, int len) {
  x.resize(len, 0);
  if (len == 1) {
    poly res;
    res.push_back(1);
    return res;
  }

  poly y = getExp(x, (len + 1) >> 1);
  poly u = x, v = y, w = y, res;
  w.resize(len, 0);
  w = getLn(w);

  prework(len << 1);
  u[0] = (u[0] + 1 - w[0] + P) % P;
  for (int i = 1; i < (int)u.size(); i++)
    u[i] = (u[i] - w[i] + P) % P;

  ntt(u, 1), ntt(v, 1);
  for (int i = 0; i < lim; i++)
    res.push_back(u[i] * v[i] % P);
  ntt(res, -1);

  res.resize(len);
  return res;
}

inline poly fpow(poly x, ll y, int n) {
  x = getLn(x);
  for (int i = 0; i < n; i++)
    x[i] = x[i] * y % P;
  x = getExp(x, n);
  return x;
}

inline poly getDiv(poly x, poly y) {
  poly u = x, v = y, res;

  reverse(u.begin(), u.end());
  reverse(v.begin(), v.end());

  int len = x.size() - y.size() + 1;
  u.resize(len, 0), v.resize(len, 0);

  res = getInv(v, len);

  res = mul(u, res);
  res.resize(len);

  reverse(res.begin(), res.end());

  return res;
}

inline poly getRest(poly x, poly y) {
  poly u = x, v = y, res = getDiv(x, y);

  v = mul(v, res);
  res = u;
  int len = max(u.size(), v.size());
  res.resize(len, 0), v.resize(len, 0);
  for (int i = 0; i < len; i++)
    res[i] = (res[i] - v[i] + P) % P;

  for (; !res.empty() && !res[res.size() - 1]; res.pop_back())
    ;
  return res;
}

} // namespace Poly

poly a[maxn];
struct cmp {
  bool operator()(const int &i, const int &j) const {
    return a[i].size() == a[j].size() ? i > j : a[i].size() > a[j].size();
  }
};
priority_queue<int, vector<int>, cmp> Q;

int main() {
  pre();
  scanf("%d", &n);
  for (int i = 1; i <= 2 * n; ++i) {
    scanf("%d", &h[i]);
    m = max(m, h[i]);
    ++cnt[h[i]];
  }
  ll ans = getinv(bin[n]), sum = 0;
  for (int i = 1; i <= m; ++i)
    if (cnt[i]) {
      int k = cnt[i];
      a[++tot] = poly(k / 2 + 1);
      for (int j = k / 2; ~j; --j)
        a[tot][j] = facinv[j] * facinv[k - 2 * j] % mod;
      ans = ans * fac[k] % mod;
      Q.push(tot);
    }
  while (Q.size() > 1) {
    int x = Q.top();
    Q.pop();
    int y = Q.top();
    Q.pop();
    // cout << x << ' ' << y << ' ' << a[x].size() << ' ' << a[y].size() <<
    // endl;
    a[++tot] = Poly::mul(a[x], a[y]);
    Q.push(tot);
  }
  for (int j = min((int)a[tot].size() - 1, n); ~j; --j) {
    ll cof = fac[2 * (n - j)] * facinv[n - j] % mod;
    if (j & 1)
      sum = (sum + mod - a[tot][j] * cof % mod) % mod;
    else
      sum = (sum + a[tot][j] * cof % mod) % mod;
  }
  // cout << sum << endl;
  ans = ans * sum % mod;
  printf("%lld\\n", ans);
  return 0;
}


Error: 0

Fixed submission:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int maxn = 200000 + 10;
ll fac[maxn], inv[maxn], facinv[maxn], bin[maxn];
ll powMod(ll x, ll k) {
  ll ret = 1;
  while (k) {
    if (k & 1)
      ret = ret * x % mod;
    x = x * x % mod;
    k >>= 1;
  }
  return ret;
}
ll getinv(ll x) { return powMod(x, mod - 2); }
void pre() {
  fac[0] = 1;
  for (int i = 1; i < maxn; ++i)
    fac[i] = fac[i - 1] * i % mod;
  inv[1] = 1;
  for (int i = 2; i < maxn; ++i)
    inv[i] = (mod - mod / i) * inv[mod % i] % mod;
  facinv[0] = 1;
  for (int i = 1; i < maxn; ++i)
    facinv[i] = facinv[i - 1] * inv[i] % mod;
  bin[0] = 1;
  for (int i = 1; i < maxn; ++i)
    bin[i] = bin[i - 1] * 2 % mod;
}
ll C(int n, int m) {
  return n < m ? 0 : fac[n] * facinv[m] % mod * facinv[n - m] % mod;
}
int h[maxn], cnt[maxn];
int n, m, tot;

typedef vector<ll> poly;

namespace Poly {
const int L = 1 << 20;
const ll P = mod;

int lim, pos[L];

inline void deb(poly c) {
  for (int i = 0; i < (int)c.size(); i++)
    printf("%lld%c", c[i], " \\n"[i == (int)c.size() - 1]);
}

inline ll fpow(ll x, ll y) {
  ll res = 1;
  for (; y > 0; y >>= 1) {
    if (y & 1)
      res = res * x % P;
    x = x * x % P;
  }
  return res;
}

const ll inv2 = fpow(2, P - 2);

template <typename T> inline void inc(T &x, T y) {
  x += y;
  if (x >= P)
    x -= P;
}

template <typename T> inline void sub(T &x, T y) {
  x -= y;
  if (x < 0)
    x += P;
}

inline void prework(int len) {
  int l = 0;
  for (lim = 1; lim < len; lim <<= 1, ++l)
    ;
  for (int i = 0; i < lim; i++)
    pos[i] = (pos[i >> 1] >> 1) | ((i & 1) << (l - 1));
}

inline void ntt(poly &c, int opt) {
  c.resize(lim, 0);
  for (int i = 0; i < lim; i++)
    if (i < pos[i])
      swap(c[i], c[pos[i]]);
  for (int i = 1; i < lim; i <<= 1) {
    ll wn = fpow(5, (P - 1) / (i << 1));
    if (opt == -1)
      wn = fpow(wn, P - 2);
    for (int len = i << 1, j = 0; j < lim; j += len) {
      ll w = 1;
      for (int k = 0; k < i; k++, w = w * wn % P) {
        ll x = c[j + k], y = w * c[j + k + i] % P;
        c[j + k] = (x + y) % P, c[j + k + i] = (x - y + P) % P;
      }
    }
  }

  if (opt == -1) {
    ll inv = fpow(lim, P - 2);
    for (int i = 0; i < lim; i++)
      c[i] = c[i] * inv % P;
  }
}

inline poly operator*(const poly &x, const poly &y) {
  poly res, u = x, v = y;
  prework(u.size() + v.size() - 1);
  ntt(u, 1), ntt(v, 1);
  for (int i = 0; i < lim; i++)
    res.push_back(v[i] * u[i] % P);
  ntt(res, -1);
  res.resize(u.size() + v.size() - 1);
  return res;
}

poly mul(const poly &x, const poly &y) { return x * y; }

poly getInv(poly x, int len) {
  x.resize(len);
  if (len == 1) {
    poly res;
    res.push_back(fpow(x[0], P - 2));
    return res;
  }
  poly y = getInv(x, (len + 1) >> 1);
  prework(len << 1);

  poly u = x, v = y, res;
  ntt(u, 1), ntt(v, 1);
  for (int i = 0; i < lim; i++)
    res.push_back(v[i] * (2LL - u[i] * v[i] % P + P) % P);
  ntt(res, -1);

  res.resize(len);
  return res;
}

inline void direv(poly &c) {
  for (int i = 0; i < (int)c.size() - 1; i++)
    c[i] = c[i + 1] * (i + 1) % P;
  c[c.size() - 1] = 0;
}

inline void integ(poly &c) {
  for (int i = (int)c.size() - 1; i > 0; i--)
    c[i] = c[i - 1] * fpow(i, P - 2) % P;
  c[0] = 0;
}

inline poly getLn(poly c) {
  poly a = getInv(c, (int)c.size());
  poly b = c;
  direv(b);

  poly res = b * a;
  res.resize(c.size());
  integ(res);
  return res;
}

poly getSqrt(poly x, int len) {
  x.resize(len);
  if (len == 1) {
    poly res;
    res.push_back(sqrt(x[0]));
    return res;
  }
  poly y = getSqrt(x, (len + 1) >> 1);
  poly u = x, v = y, w, res;
  w = getInv(y, len);

  prework(len << 1);
  ntt(u, 1), ntt(v, 1), ntt(w, 1);
  for (int i = 0; i < lim; i++)
    res.push_back((v[i] * v[i] % P + u[i]) % P * w[i] % P * inv2 % P);
  ntt(res, -1);
  res.resize(len);

  return res;
}

poly getExp(poly x, int len) {
  x.resize(len, 0);
  if (len == 1) {
    poly res;
    res.push_back(1);
    return res;
  }

  poly y = getExp(x, (len + 1) >> 1);
  poly u = x, v = y, w = y, res;
  w.resize(len, 0);
  w = getLn(w);

  prework(len << 1);
  u[0] = (u[0] + 1 - w[0] + P) % P;
  for (int i = 1; i < (int)u.size(); i++)
    u[i] = (u[i] - w[i] + P) % P;

  ntt(u, 1), ntt(v, 1);
  for (int i = 0; i < lim; i++)
    res.push_back(u[i] * v[i] % P);
  ntt(res, -1);

  res.resize(len);
  return res;
}

inline poly fpow(poly x, ll y, int n) {
  x = getLn(x);
  for (int i = 0; i < n; i++)
    x[i] = x[i] * y % P;
  x = getExp(x, n);
  return x;
}

inline poly getDiv(poly x, poly y) {
  poly u = x, v = y, res;

  reverse(u.begin(), u.end());
  reverse(v.begin(), v.end());

  int len = x.size() - y.size() + 1;
  u.resize(len, 0), v.resize(len, 0);

  res = getInv(v, len);

  res = mul(u, res);
  res.resize(len);

  reverse(res.begin(), res.end());

  return res;
}

inline poly getRest(poly x, poly y) {
  poly u = x, v = y, res = getDiv(x, y);

  v = mul(v, res);
  res = u;
  int len = max(u.size(), v.size());
  res.resize(len, 0), v.resize(len, 0);
  for (int i = 0; i < len; i++)
    res[i] = (res[i] - v[i] + P) % P;

  for (; !res.empty() && !res[res.size() - 1]; res.pop_back())
    ;
  return res;
}

} // namespace Poly

poly a[maxn];
struct cmp {
  bool operator()(const int &i, const int &j) const {
    return a[i].size() == a[j].size() ? i > j : a[i].size() > a[j].size();
  }
};
priority_queue<int, vector<int>, cmp> Q;

int main() {
  pre();
  scanf("%d", &n);
  for (int i = 1; i <= 2 * n; ++i) {
    scanf("%d", &h[i]);
    m = max(m, h[i]);
    ++cnt[h[i]];
  }
  ll ans = getinv(bin[n]), sum = 0;
  for (int i = 1; i <= m; ++i)
    if (cnt[i]) {
      int k = cnt[i];
      a[++tot] = poly(k / 2 + 1);
      for (int j = k / 2; ~j; --j)
        a[tot][j] = facinv[j] * facinv[k - 2 * j] % mod;
      ans = ans * fac[k] % mod;
      Q.push(tot);
    }
  while (Q.size() > 1) {
    int x = Q.top();
    Q.pop();
    int y = Q.top();
    Q.pop();
    a[++tot] = Poly::mul(a[x], a[y]);
    Q.push(tot);
  }
  for (int j = min((int)a[tot].size() - 1, n); ~j; --j) {
    ll cof = fac[2 * (n - j)] * facinv[n - j] % mod;
    if (j & 1)
      sum = (sum + mod - a[tot][j] * cof % mod) % mod;
    else
      sum = (sum + a[tot][j] * cof % mod) % mod;
  }
  // cout << sum << endl;
  ans = ans * sum % mod;
  printf("%lld\\n", ans);
  return 0;
}