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

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
typedef long double ld;

#ifdef LOCAL
#define Gene template <class
#define Rics printer &operator,
Gene c > struct rge {
  c b, e;
};
Gene c > rge<c> range(c i, c j) { return {i, j}; }
struct printer {
  ~printer() { cerr << endl; }
  Gene c > Rics(c x) {
    cerr << boolalpha << x;
    return *this;
  }
  Rics(string x) {
    cerr << x;
    return *this;
  }
  Gene c, class d > Rics(pair<c, d> x) {
    return *this, "(", x.first, ", ", x.second, ")";
  }
  Gene... d, Gene... > class c > Rics(c<d...> x) {
    return *this, range(begin(x), end(x));
  }
  Gene c > Rics(rge<c> x) {
    *this, "[";
    for (auto it = x.b; it != x.e; ++it)
      *this, (it == x.b ? "" : ", "), *it;
    return *this, "]";
  }
};
#define debug() cerr << "LINE " << __LINE__ << " >> ", printer()
#define dbg(x) "[", #x, ": ", (x), "] "
#define bits(x) bitset<22>(x)
#define tham getchar()
#endif

#define FASTIO                                                                 \\
  ios_base::sync_with_stdio(false);                                            \\
  cin.tie(NULL);                                                               \\
  cout.tie(NULL);
#define eq(x, y) (fabs((x) - (y)) < error)
#define bt(i) (1LL << (i))

mt19937_64
    rng((unsigned)chrono::system_clock::now().time_since_epoch().count());
const ll mod = 998244353;
// const ld error = ;
const ld PI = acosl(-1);

// inline ll MOD(ll x, ll m = mod){
//     ll y = x % m;
//     return (y >= 0) ? y: y+m;
// }

// const int/ll inf = ;
const int nmax = 1e5 + 10;
///===========================================  template
///=======================================================

ll modexpo(ll x, ll n, ll m) {
  ll ret = 1;
  while (n) {
    if (n & 1)
      ret = ret * x % m;
    x = x * x % m;
    n >>= 1;
  }
  return ret;
}

typedef ll T;
typedef vector<T> poly;
poly roots; // precomputed roots
ll M;       // mod to be remembered
int N;      // size of stored roots
// m = prime mod, rt = primitve root, max_n = maximum root precal
int precal(ll m, ll rt, int max_n = bt(22)) {
  ll k = (m - 1);
  N = 1, M = m;
  while (!(k & 1) && N < max_n)
    k >>= 1, N <<= 1;
  roots.resize(N + 1);
  rt = modexpo(rt, k, M);
  roots[0] = 1;
  for (int i = 1; i <= N; i++)
    roots[i] = roots[i - 1] * rt % M;
  return N; // returns how many precalculated
}

#define nxt(i, m) ((i) ^ m ^ (bt(31 - __builtin_clz((i) ^ m)) - 1))
//^this returns next to i after reversing w.r.t mask m

void NTT(poly &coefs, poly &values,
         bool invert = false) // invert -> inverse DFT
{
  int n = (int)coefs.size(), lg_n = __builtin_ctz(n), mask = (int)bt(lg_n) - 1;
  values.resize(n); // coefs MUST BE of size 2^k

  for (int i = 0, j = 0; j < n; j++, i = (int)nxt(i, mask))
    values[j] = coefs[i]; // filling values with ordered coefficients

  for (int len = 2, hlen = 1; len <= n;
       len <<= 1, hlen <<= 1)                     // recursions from base level
    for (int i = 0; i < n; i += len)              // each part in a level
      for (int j = 0, r = N / len; j < hlen; j++) // the recursion
      {
        T w = (invert) ? roots[N - j * r] : roots[j * r];
        T u = values[i + j], v = values[i + j + hlen] * w % M;
        values[i + j] = u + v;
        if (values[i + j] >= M)
          values[i + j] -= M;
        values[i + j + hlen] = u - v;
        if (values[i + j + hlen] < 0)
          values[i + j + hlen] += M;
      }

  if (invert) {
    ll inv_n = modexpo(n, M - 2, M);
    for (auto &x : values)
      x = x * inv_n % M; // final division if inverting
  }
}

void multiply(poly &A, poly &B, poly &C) // result is stored in C
{
  poly va, vb;
  int a = (int)A.size(), b = (int)B.size(), n = 1;
  while (n < a + b)
    n <<= 1;
  A.resize(n), B.resize(n); // making polynomials large enough

  NTT(A, va), NTT(B, vb); // NTT
  for (int i = 0; i < n; i++)
    va[i] = va[i] * vb[i] % mod; // mod if NTT
  NTT(va, C, true);              // NTT inverse

  C.resize(a + b - 1);
}

vector<poly> P;

ll fac[nmax];
ll facinv[nmax];

void precalNCR() {
  fac[0] = 1;
  for (int i = 1; i < nmax; i++)
    fac[i] = fac[i - 1] * i % mod;
  facinv[nmax - 1] = modexpo(fac[nmax - 1], mod - 2, mod);
  for (int i = nmax - 1; i > 0; i--)
    facinv[i - 1] = facinv[i] * i % mod;
}

ll ncr(int n, int r) {
  if (r < 0 || n < r)
    return 0;
  return fac[n] * facinv[r] % mod * facinv[n - r] % mod;
}

int cnt[nmax];
ll oddfac[nmax];

int recurse(int l, int r) {
  if (l == r)
    return l;
  int mid = (l + r) >> 1;
  int lid = recurse(l, mid);
  int rid = recurse(mid + 1, r);

  multiply(P[lid], P[rid], P[lid]);
  return lid;
}

int main() {
  FASTIO;

  precal(mod, 3, 1 << 20);
  precalNCR();

  int n;
  cin >> n;
  for (int i = 0; i < 2 * n; i++) {
    int x;
    cin >> x;
    cnt[x]++;
  }

  oddfac[0] = 1;
  for (int i = 2; i <= 2 * n; i += 2) {
    oddfac[i] = oddfac[i - 2] * (i - 1) % mod;
  }

  P.emplace_back(1, 1);
  for (int i = 1; i < nmax; i++) {
    if (cnt[i] <= 1) {
      continue;
    }

    P.emplace_back(cnt[i] + 1);
    P.back()[0] = 1;
    for (int j = 2; j <= cnt[i]; j += 2) {
      P.back()[j] = ncr(cnt[i], j) * oddfac[j] % mod;
    }
  }

  int id = recurse(0, (int)P.size() - 1);

  ll ans = 0;
  for (int i = 0; i < P[id].size(); i += 2) {
    ll tmp = P[id][i] * oddfac[2 * n - i];
    //        debug(), dbg(tmp);
    if (i / 2 % 2 == 0) {
      ans += tmp;
    } else {
      ans -= tmp;
    }
    ans %= mod;
  }
  if (ans < 0)
    ans += mod;
  cout << ans << endl;

  return 0;
}


Error: 0

Fixed submission:

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
typedef long double ld;

#ifdef LOCAL
#define Gene template <class
#define Rics printer &operator,
Gene c > struct rge {
  c b, e;
};
Gene c > rge<c> range(c i, c j) { return {i, j}; }
struct printer {
  ~printer() { cerr << endl; }
  Gene c > Rics(c x) {
    cerr << boolalpha << x;
    return *this;
  }
  Rics(string x) {
    cerr << x;
    return *this;
  }
  Gene c, class d > Rics(pair<c, d> x) {
    return *this, "(", x.first, ", ", x.second, ")";
  }
  Gene... d, Gene... > class c > Rics(c<d...> x) {
    return *this, range(begin(x), end(x));
  }
  Gene c > Rics(rge<c> x) {
    *this, "[";
    for (auto it = x.b; it != x.e; ++it)
      *this, (it == x.b ? "" : ", "), *it;
    return *this, "]";
  }
};
#define debug() cerr << "LINE " << __LINE__ << " >> ", printer()
#define dbg(x) "[", #x, ": ", (x), "] "
#define bits(x) bitset<22>(x)
#define tham getchar()
#endif

#define FASTIO                                                                 \\
  ios_base::sync_with_stdio(false);                                            \\
  cin.tie(NULL);                                                               \\
  cout.tie(NULL);
#define eq(x, y) (fabs((x) - (y)) < error)
#define bt(i) (1LL << (i))

mt19937_64
    rng((unsigned)chrono::system_clock::now().time_since_epoch().count());
const ll mod = 998244353;
// const ld error = ;
const ld PI = acosl(-1);

// inline ll MOD(ll x, ll m = mod){
//     ll y = x % m;
//     return (y >= 0) ? y: y+m;
// }

// const int/ll inf = ;
const int nmax = 1e5 + 10;
///===========================================  template
///=======================================================

ll modexpo(ll x, ll n, ll m) {
  ll ret = 1;
  while (n) {
    if (n & 1)
      ret = ret * x % m;
    x = x * x % m;
    n >>= 1;
  }
  return ret;
}

typedef ll T;
typedef vector<T> poly;
poly roots; // precomputed roots
ll M;       // mod to be remembered
int N;      // size of stored roots
// m = prime mod, rt = primitve root, max_n = maximum root precal
int precal(ll m, ll rt, int max_n = bt(22)) {
  ll k = (m - 1);
  N = 1, M = m;
  while (!(k & 1) && N < max_n)
    k >>= 1, N <<= 1;
  roots.resize(N + 1);
  rt = modexpo(rt, k, M);
  roots[0] = 1;
  for (int i = 1; i <= N; i++)
    roots[i] = roots[i - 1] * rt % M;
  return N; // returns how many precalculated
}

#define nxt(i, m) ((i) ^ m ^ (bt(31 - __builtin_clz((i) ^ m)) - 1))
//^this returns next to i after reversing w.r.t mask m

void NTT(poly &coefs, poly &values,
         bool invert = false) // invert -> inverse DFT
{
  int n = (int)coefs.size(), lg_n = __builtin_ctz(n), mask = (int)bt(lg_n) - 1;
  values.resize(n); // coefs MUST BE of size 2^k

  for (int i = 0, j = 0; j < n; j++, i = (int)nxt(i, mask))
    values[j] = coefs[i]; // filling values with ordered coefficients

  for (int len = 2, hlen = 1; len <= n;
       len <<= 1, hlen <<= 1)                     // recursions from base level
    for (int i = 0; i < n; i += len)              // each part in a level
      for (int j = 0, r = N / len; j < hlen; j++) // the recursion
      {
        T w = (invert) ? roots[N - j * r] : roots[j * r];
        T u = values[i + j], v = values[i + j + hlen] * w % M;
        values[i + j] = u + v;
        if (values[i + j] >= M)
          values[i + j] -= M;
        values[i + j + hlen] = u - v;
        if (values[i + j + hlen] < 0)
          values[i + j + hlen] += M;
      }

  if (invert) {
    ll inv_n = modexpo(n, M - 2, M);
    for (auto &x : values)
      x = x * inv_n % M; // final division if inverting
  }
}

void multiply(poly &A, poly &B, poly &C) // result is stored in C
{
  poly va, vb;
  int a = (int)A.size(), b = (int)B.size(), n = 1;
  while (n < a + b)
    n <<= 1;
  A.resize(n), B.resize(n); // making polynomials large enough

  NTT(A, va), NTT(B, vb); // NTT
  for (int i = 0; i < n; i++)
    va[i] = va[i] * vb[i] % mod; // mod if NTT
  NTT(va, C, true);              // NTT inverse

  C.resize(a + b - 1);
}

vector<poly> P;

ll fac[nmax];
ll facinv[nmax];

void precalNCR() {
  fac[0] = 1;
  for (int i = 1; i < nmax; i++)
    fac[i] = fac[i - 1] * i % mod;
  facinv[nmax - 1] = modexpo(fac[nmax - 1], mod - 2, mod);
  for (int i = nmax - 1; i > 0; i--)
    facinv[i - 1] = facinv[i] * i % mod;
}

ll ncr(int n, int r) {
  if (r < 0 || n < r)
    return 0;
  return fac[n] * facinv[r] % mod * facinv[n - r] % mod;
}

int cnt[nmax];
ll oddfac[nmax];

int recurse(int l, int r) {
  if (l == r)
    return l;
  int mid = (l + r) >> 1;
  int lid = recurse(l, mid);
  int rid = recurse(mid + 1, r);

  multiply(P[lid], P[rid], P[lid]);
  return lid;
}

int main() {
  FASTIO;

  precal(mod, 3, 1 << 20);
  precalNCR();

  int n;
  cin >> n;
  for (int i = 0; i < 2 * n; i++) {
    int x;
    cin >> x;
    cnt[x]++;
  }

  oddfac[0] = 1;
  for (int i = 2; i <= 2 * n; i += 2) {
    oddfac[i] = oddfac[i - 2] * (i - 1) % mod;
  }

  for (int i = 1; i < nmax; i++) {
    if (cnt[i] <= 1) {
      continue;
    }

    P.emplace_back(cnt[i] + 1);
    P.back()[0] = 1;
    ll tmp = 1;
    for (int j = 2; j <= cnt[i]; j += 2) {
      P.back()[j] = ncr(cnt[i], j) * oddfac[j] % mod;
    }
  }

  int id = recurse(0, (int)P.size() - 1);

  ll ans = 0;
  for (int i = 0; i < P[id].size(); i += 2) {
    ll tmp = P[id][i] * oddfac[2 * n - i];
    //        debug(), dbg(tmp);
    if (i / 2 % 2 == 0) {
      ans += tmp;
    } else {
      ans -= tmp;
    }
    ans %= mod;
  }
  if (ans < 0)
    ans += mod;
  cout << ans << endl;

  return 0;
}