Problem p02539 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>
#define F first
#define S second
using namespace std;
const int MOD = 998244353;
const int mod = MOD;
typedef long long ll;
typedef long long LL;
const int maxn = 5e4 + 5;
ll pre[maxn], inv[maxn], prei[maxn];
void build(int n) {
  pre[1] = pre[0] = inv[1] = inv[0] = prei[1] = prei[0] = 1;
  for (int i = 2; i <= n; i++) {
    pre[i] = pre[i - 1] * i % mod;
    inv[i] = (mod - mod / i * inv[mod % i] % mod) % mod;
    prei[i] = prei[i - 1] * inv[i] % mod;
  }
}
ll PP(int n, int k) { return pre[n] * prei[n - k] % mod; }
int fpow(int a, int n, int P) {
  int r = 1;
  while (n) {
    if (n & 1)
      r = 1ll * r * a % P;
    a = 1ll * a * a % P;
    n >>= 1;
  }
  return r;
}
const int P = 998244353, R = 3, MAXN = (1 << 23);
struct Poly : vector<int> {
  int n;
  Poly(int n) : n(n) { this->resize(n); }
  int extend(int x) {
    int N = 1;
    while (N < x)
      N <<= 1;
    return N;
  }
  Poly operator*(const Poly &rhs) {
    Poly a = *this, b = rhs;
    int N = extend(n + rhs.n - 1);
    a.resize(a.n = N);
    a.ntt(1);
    b.resize(b.n = N);
    b.ntt(1);
    for (int i = 0; i < N; i++)
      a[i] = 1ll * a[i] * b[i] % P;
    return a.ntt(-1), a.n = n + rhs.n, a;
  }
  void ntt(int op) {
    static Poly r(MAXN);
    for (int i = 0; i < n; i++) {
      r[i] = (i & 1) * (n >> 1) + (r[i >> 1] >> 1);
      if (r[i] < i)
        std::swap(at(i), at(r[i]));
    }
    for (int m = 2; m <= n; m <<= 1) {
      int k = m >> 1, gn = fpow(R, (P - 1) / m, P);
      for (int i = 0; i < n; i += m) {
        int g = 1;
        for (int j = 0; j < k; j++, g = 1ll * g * gn % P) {
          int tmp = 1ll * at(i + j + k) * g % P;
          at(i + j + k) = (at(i + j) - tmp + P) % P;
          at(i + j) = (at(i + j) + tmp) % P;
        }
      }
    }
    if (op == -1) {
      reverse(begin() + 1, end());
      int inv = fpow(n, P - 2, P);
      for (int i = 0; i < n; i++)
        at(i) = 1ll * at(i) * inv % P;
    }
  }
  bool operator<(const Poly &rhs) const { return n > rhs.n; }
};
typedef pair<int, int> pii;
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  build(maxn - 1);
  int n;
  cin >> n;
  map<int, int> cnt;
  for (int i = 0; i < 2 * n; i++) {
    int v;
    cin >> v;
    cnt[v]++;
  }
  n *= 2;

  priority_queue<Poly> pq;
  for (auto &p : cnt) {
    int k = p.S / 2;
    Poly poly(k + 1);
    for (int i = 0; i <= k; i++) {
      poly[i] = PP(p.S, 2 * i) * fpow(fpow(2, i, MOD), MOD - 2, MOD) % MOD *
                prei[i] % MOD;
    }
    //        cout << p.F << ' ' << p.S << ": ";
    //        for (int i = 0 ; i <= k ; i++)
    //            cout << poly[i] << ' ';
    //        cout << '\n';
    pq.push(poly);
  }
  while (pq.size() > 1) {
    auto a = pq.top();
    pq.pop();
    auto b = pq.top();
    pq.pop();
    pq.push(a * b);
  }
  auto res = pq.top();
  pq.pop();
  //    for (int i = 0 ; i < res.n ; i++)
  //        cout << res[i] << ' ';
  //    cout << '\n';
  LL ans = 0;
  for (int i = 0; i <= n / 2; i++) {
    //        cout << i << ": " << res[i] * pre[n - 2 * i] % MOD * fpow(fpow(2,
    //        n / 2 - i, MOD), MOD - 2, MOD) % MOD * prei[n / 2 - i] % MOD <<
    //        '\n'; cout << "!: " << pre[n - 2 * i] << '\n'; cout << "/2**k: "
    //        << fpow(fpow(2, n / 2 - i, MOD), MOD - 2, MOD) << '\n'; cout <<
    //        "/n!: " << prei[n / 2 - i] << '\n';
    if (i % 2 == 0) {
      ans += res[i] * pre[n - 2 * i] % MOD *
             fpow(fpow(2, n / 2 - i, MOD), MOD - 2, MOD) % MOD *
             prei[n / 2 - i] % MOD;
      ans %= MOD;
    } else {
      ans -= res[i] * pre[n - 2 * i] % MOD *
             fpow(fpow(2, n / 2 - i, MOD), MOD - 2, MOD) % MOD *
             prei[n / 2 - i] % MOD;
      ans += MOD;
      ans %= MOD;
    }
  }
  cout << ans << '\n';
}


Fixed submission:
#include <bits/stdc++.h>
#define F first
#define S second
using namespace std;
const int MOD = 998244353;
const int mod = MOD;
typedef long long ll;
typedef long long LL;
const int maxn = 2e5 + 5;
ll pre[maxn], inv[maxn], prei[maxn];
void build(int n) {
  pre[1] = pre[0] = inv[1] = inv[0] = prei[1] = prei[0] = 1;
  for (int i = 2; i <= n; i++) {
    pre[i] = pre[i - 1] * i % mod;
    inv[i] = (mod - mod / i * inv[mod % i] % mod) % mod;
    prei[i] = prei[i - 1] * inv[i] % mod;
  }
}
ll PP(int n, int k) { return pre[n] * prei[n - k] % mod; }
int fpow(int a, int n, int P) {
  int r = 1;
  while (n) {
    if (n & 1)
      r = 1ll * r * a % P;
    a = 1ll * a * a % P;
    n >>= 1;
  }
  return r;
}
const int P = 998244353, R = 3, MAXN = (1 << 23);
struct Poly : vector<int> {
  int n;
  Poly(int n) : n(n) { this->resize(n); }
  int extend(int x) {
    int N = 1;
    while (N < x)
      N <<= 1;
    return N;
  }
  Poly operator*(const Poly &rhs) {
    Poly a = *this, b = rhs;
    int N = extend(n + rhs.n - 1);
    a.resize(a.n = N);
    a.ntt(1);
    b.resize(b.n = N);
    b.ntt(1);
    for (int i = 0; i < N; i++)
      a[i] = 1ll * a[i] * b[i] % P;
    return a.ntt(-1), a.n = n + rhs.n, a;
  }
  void ntt(int op) {
    static Poly r(MAXN);
    for (int i = 0; i < n; i++) {
      r[i] = (i & 1) * (n >> 1) + (r[i >> 1] >> 1);
      if (r[i] < i)
        std::swap(at(i), at(r[i]));
    }
    for (int m = 2; m <= n; m <<= 1) {
      int k = m >> 1, gn = fpow(R, (P - 1) / m, P);
      for (int i = 0; i < n; i += m) {
        int g = 1;
        for (int j = 0; j < k; j++, g = 1ll * g * gn % P) {
          int tmp = 1ll * at(i + j + k) * g % P;
          at(i + j + k) = (at(i + j) - tmp + P) % P;
          at(i + j) = (at(i + j) + tmp) % P;
        }
      }
    }
    if (op == -1) {
      reverse(begin() + 1, end());
      int inv = fpow(n, P - 2, P);
      for (int i = 0; i < n; i++)
        at(i) = 1ll * at(i) * inv % P;
    }
  }
  bool operator<(const Poly &rhs) const { return n > rhs.n; }
};
typedef pair<int, int> pii;
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  build(maxn - 1);
  int n;
  cin >> n;
  map<int, int> cnt;
  for (int i = 0; i < 2 * n; i++) {
    int v;
    cin >> v;
    cnt[v]++;
  }
  n *= 2;

  priority_queue<Poly> pq;
  for (auto &p : cnt) {
    int k = p.S / 2;
    Poly poly(k + 1);
    for (int i = 0; i <= k; i++) {
      poly[i] = PP(p.S, 2 * i) * fpow(fpow(2, i, MOD), MOD - 2, MOD) % MOD *
                prei[i] % MOD;
    }
    //        cout << p.F << ' ' << p.S << ": ";
    //        for (int i = 0 ; i <= k ; i++)
    //            cout << poly[i] << ' ';
    //        cout << '\n';
    pq.push(poly);
  }
  while (pq.size() > 1) {
    auto a = pq.top();
    pq.pop();
    auto b = pq.top();
    pq.pop();
    pq.push(a * b);
  }
  auto res = pq.top();
  pq.pop();
  //    for (int i = 0 ; i < res.n ; i++)
  //        cout << res[i] << ' ';
  //    cout << '\n';
  LL ans = 0;
  for (int i = 0; i <= n / 2; i++) {
    //        cout << i << ": " << res[i] * pre[n - 2 * i] % MOD * fpow(fpow(2,
    //        n / 2 - i, MOD), MOD - 2, MOD) % MOD * prei[n / 2 - i] % MOD <<
    //        '\n'; cout << "!: " << pre[n - 2 * i] << '\n'; cout << "/2**k: "
    //        << fpow(fpow(2, n / 2 - i, MOD), MOD - 2, MOD) << '\n'; cout <<
    //        "/n!: " << prei[n / 2 - i] << '\n';
    if (i % 2 == 0) {
      ans += res[i] * pre[n - 2 * i] % MOD *
             fpow(fpow(2, n / 2 - i, MOD), MOD - 2, MOD) % MOD *
             prei[n / 2 - i] % MOD;
      ans %= MOD;
    } else {
      ans -= res[i] * pre[n - 2 * i] % MOD *
             fpow(fpow(2, n / 2 - i, MOD), MOD - 2, MOD) % MOD *
             prei[n / 2 - i] % MOD;
      ans += MOD;
      ans %= MOD;
    }
  }
  cout << ans << '\n';
}