Problem p02539 (C++)

Buggy submission (status: Runtime Error):
#include "algorithm"
#include "bitset"
#include "cassert"
#include "climits"
#include "cmath"
#include "cstdio"
#include "ctime"
#include "functional"
#include "iomanip"
#include "iostream"
#include "list"
#include "map"
#include "numeric"
#include "queue"
#include "random"
#include "set"
#include "stack"
#include "string"
#include "unordered_map"
#include "unordered_set"

using namespace std;

// constexpr long long int MOD = 1000000007;
// constexpr int MOD = 1000000007;
// constexpr int MOD = 998244353;
constexpr long long int MOD = 998244353;
constexpr double EPS = 1e-5;

// int N, M, K, T, H, W, L, R;
long long int N, M, K, T, H, W, L, R;

template <int mod> struct NumberTheoreticTransform {

  vector<int> rev, rts;
  int base, max_base, root;

  NumberTheoreticTransform() : base(1), rev{0, 1}, rts{0, 1} {
    assert(mod >= 3 && mod % 2 == 1);
    auto tmp = mod - 1;
    max_base = 0;
    while (tmp % 2 == 0)
      tmp >>= 1, max_base++;
    root = 2;
    while (mod_pow(root, (mod - 1) >> 1) == 1)
      ++root;
    assert(mod_pow(root, mod - 1) == 1);
    root = mod_pow(root, (mod - 1) >> max_base);
  }

  inline int mod_pow(int x, int n) {
    int ret = 1;
    while (n > 0) {
      if (n & 1)
        ret = mul(ret, x);
      x = mul(x, x);
      n >>= 1;
    }
    return ret;
  }

  inline int inverse(int x) { return mod_pow(x, mod - 2); }

  inline unsigned add(unsigned x, unsigned y) {
    x += y;
    if (x >= mod)
      x -= mod;
    return x;
  }

  inline unsigned mul(unsigned a, unsigned b) {
    return 1ull * a * b % (unsigned long long)mod;
  }

  void ensure_base(int nbase) {
    if (nbase <= base)
      return;
    rev.resize(1 << nbase);
    rts.resize(1 << nbase);
    for (int i = 0; i < (1 << nbase); i++) {
      rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (nbase - 1));
    }
    assert(nbase <= max_base);
    while (base < nbase) {
      int z = mod_pow(root, 1 << (max_base - 1 - base));
      for (int i = 1 << (base - 1); i < (1 << base); i++) {
        rts[i << 1] = rts[i];
        rts[(i << 1) + 1] = mul(rts[i], z);
      }
      ++base;
    }
  }

  void ntt(vector<int> &a) {
    const int n = (int)a.size();
    assert((n & (n - 1)) == 0);
    int zeros = __builtin_ctz(n);
    ensure_base(zeros);
    int shift = base - zeros;
    for (int i = 0; i < n; i++) {
      if (i < (rev[i] >> shift)) {
        swap(a[i], a[rev[i] >> shift]);
      }
    }
    for (int k = 1; k < n; k <<= 1) {
      for (int i = 0; i < n; i += 2 * k) {
        for (int j = 0; j < k; j++) {
          int z = mul(a[i + j + k], rts[j + k]);
          a[i + j + k] = add(a[i + j], mod - z);
          a[i + j] = add(a[i + j], z);
        }
      }
    }
  }

  vector<int> multiply(vector<int> a, vector<int> b) {
    int need = a.size() + b.size() - 1;
    int nbase = 1;
    while ((1 << nbase) < need)
      nbase++;
    ensure_base(nbase);
    int sz = 1 << nbase;
    a.resize(sz, 0);
    b.resize(sz, 0);
    ntt(a);
    ntt(b);
    int inv_sz = inverse(sz);
    for (int i = 0; i < sz; i++) {
      a[i] = mul(a[i], mul(b[i], inv_sz));
    }
    reverse(a.begin() + 1, a.end());
    ntt(a);
    a.resize(need);
    return a;
  }
};

long long int power(long long int x, long long int n, long long int M) {
  long long int ret = 1;
  long long int by = x;
  while (n) {
    if (n & 1) {
      ret *= by;
      ret %= M;
    }
    by *= by;
    by %= M;
    n >>= 1;
  }
  return ret;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);

  cin >> N;
  vector<int> num(100001);
  for (int i = 0; i < 2 * N; i++) {
    cin >> M;
    num[M]++;
  }
  NumberTheoreticTransform<998244353> ntt;
  vector<vector<int>> box(100001);
  vector<long long int> by(200001, 1);
  vector<long long int> rev(200001, 1);
  for (int i = 1; i <= 200000; i++) {
    by[i] = by[i - 1] * i % MOD;
    rev[i] = power(by[i], MOD - 2, MOD);
  }
  priority_queue<pair<int, int>, vector<pair<int, int>>,
                 greater<pair<int, int>>>
      PQ;
  for (int i = 1; i <= 100000; i++) {
    if (num[i] / 2 == 0)
      continue;
    vector<int> v(num[i] / 2 + 1, 1);
    for (int j = 1; j <= num[i] / 2; j++) {
      v[j] = by[num[i]] * rev[num[i] - 2 * j] % MOD * rev[j] % MOD *
             power(rev[2], j, MOD) % MOD;
      ;
    }
    box[i] = v;
    PQ.push({num[i] / 2, i});
  }
  if (!PQ.empty()) {
    cout << by[N * 2] % MOD * rev[N] % MOD * power(rev[2], N, MOD) % MOD
         << endl;
    return 0;
  }
  while (PQ.size() > 1) {
    auto a = PQ.top();
    PQ.pop();
    auto b = PQ.top();
    PQ.pop();
    box[a.second] = ntt.multiply(box[a.second], box[b.second]);
    PQ.push({box[a.second].size() - 1, a.second});
  }
  long long int ans = 0;
  for (int i = 0; i <= PQ.top().first; i++) {
    if (i & 1) {
      ans += MOD - box[PQ.top().second][i] * by[N * 2 - i * 2] % MOD *
                       rev[N - i] % MOD * power(rev[2], N - i, MOD) % MOD;
    } else {
      ans += box[PQ.top().second][i] * by[N * 2 - i * 2] % MOD * rev[N - i] %
             MOD * power(rev[2], N - i, MOD) % MOD;
    }
  }
  cout << ans % MOD << endl;
}


Fixed submission:
#include "algorithm"
#include "bitset"
#include "cassert"
#include "climits"
#include "cmath"
#include "cstdio"
#include "ctime"
#include "functional"
#include "iomanip"
#include "iostream"
#include "list"
#include "map"
#include "numeric"
#include "queue"
#include "random"
#include "set"
#include "stack"
#include "string"
#include "unordered_map"
#include "unordered_set"

using namespace std;

// constexpr long long int MOD = 1000000007;
// constexpr int MOD = 1000000007;
// constexpr int MOD = 998244353;
constexpr long long int MOD = 998244353;
constexpr double EPS = 1e-5;

// int N, M, K, T, H, W, L, R;
long long int N, M, K, T, H, W, L, R;

template <int mod> struct NumberTheoreticTransform {

  vector<int> rev, rts;
  int base, max_base, root;

  NumberTheoreticTransform() : base(1), rev{0, 1}, rts{0, 1} {
    assert(mod >= 3 && mod % 2 == 1);
    auto tmp = mod - 1;
    max_base = 0;
    while (tmp % 2 == 0)
      tmp >>= 1, max_base++;
    root = 2;
    while (mod_pow(root, (mod - 1) >> 1) == 1)
      ++root;
    assert(mod_pow(root, mod - 1) == 1);
    root = mod_pow(root, (mod - 1) >> max_base);
  }

  inline int mod_pow(int x, int n) {
    int ret = 1;
    while (n > 0) {
      if (n & 1)
        ret = mul(ret, x);
      x = mul(x, x);
      n >>= 1;
    }
    return ret;
  }

  inline int inverse(int x) { return mod_pow(x, mod - 2); }

  inline unsigned add(unsigned x, unsigned y) {
    x += y;
    if (x >= mod)
      x -= mod;
    return x;
  }

  inline unsigned mul(unsigned a, unsigned b) {
    return 1ull * a * b % (unsigned long long)mod;
  }

  void ensure_base(int nbase) {
    if (nbase <= base)
      return;
    rev.resize(1 << nbase);
    rts.resize(1 << nbase);
    for (int i = 0; i < (1 << nbase); i++) {
      rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (nbase - 1));
    }
    assert(nbase <= max_base);
    while (base < nbase) {
      int z = mod_pow(root, 1 << (max_base - 1 - base));
      for (int i = 1 << (base - 1); i < (1 << base); i++) {
        rts[i << 1] = rts[i];
        rts[(i << 1) + 1] = mul(rts[i], z);
      }
      ++base;
    }
  }

  void ntt(vector<int> &a) {
    const int n = (int)a.size();
    assert((n & (n - 1)) == 0);
    int zeros = __builtin_ctz(n);
    ensure_base(zeros);
    int shift = base - zeros;
    for (int i = 0; i < n; i++) {
      if (i < (rev[i] >> shift)) {
        swap(a[i], a[rev[i] >> shift]);
      }
    }
    for (int k = 1; k < n; k <<= 1) {
      for (int i = 0; i < n; i += 2 * k) {
        for (int j = 0; j < k; j++) {
          int z = mul(a[i + j + k], rts[j + k]);
          a[i + j + k] = add(a[i + j], mod - z);
          a[i + j] = add(a[i + j], z);
        }
      }
    }
  }

  vector<int> multiply(vector<int> a, vector<int> b) {
    int need = a.size() + b.size() - 1;
    int nbase = 1;
    while ((1 << nbase) < need)
      nbase++;
    ensure_base(nbase);
    int sz = 1 << nbase;
    a.resize(sz, 0);
    b.resize(sz, 0);
    ntt(a);
    ntt(b);
    int inv_sz = inverse(sz);
    for (int i = 0; i < sz; i++) {
      a[i] = mul(a[i], mul(b[i], inv_sz));
    }
    reverse(a.begin() + 1, a.end());
    ntt(a);
    a.resize(need);
    return a;
  }
};

long long int power(long long int x, long long int n, long long int M) {
  long long int ret = 1;
  long long int by = x;
  while (n) {
    if (n & 1) {
      ret *= by;
      ret %= M;
    }
    by *= by;
    by %= M;
    n >>= 1;
  }
  return ret;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);

  cin >> N;
  vector<int> num(100001);
  for (int i = 0; i < 2 * N; i++) {
    cin >> M;
    num[M]++;
  }
  NumberTheoreticTransform<998244353> ntt;
  vector<vector<int>> box(100001);
  vector<long long int> by(200001, 1);
  vector<long long int> rev(200001, 1);
  for (int i = 1; i <= 200000; i++) {
    by[i] = by[i - 1] * i % MOD;
    rev[i] = power(by[i], MOD - 2, MOD);
  }
  priority_queue<pair<int, int>, vector<pair<int, int>>,
                 greater<pair<int, int>>>
      PQ;
  for (int i = 1; i <= 100000; i++) {
    if (num[i] / 2 == 0)
      continue;
    vector<int> v(num[i] / 2 + 1, 1);
    for (int j = 1; j <= num[i] / 2; j++) {
      v[j] = by[num[i]] * rev[num[i] - 2 * j] % MOD * rev[j] % MOD *
             power(rev[2], j, MOD) % MOD;
      ;
    }
    box[i] = v;
    PQ.push({num[i] / 2, i});
  }
  if (PQ.empty()) {
    cout << by[N * 2] % MOD * rev[N] % MOD * power(rev[2], N, MOD) % MOD
         << endl;
    return 0;
  }
  while (PQ.size() > 1) {
    auto a = PQ.top();
    PQ.pop();
    auto b = PQ.top();
    PQ.pop();
    box[a.second] = ntt.multiply(box[a.second], box[b.second]);
    PQ.push({box[a.second].size() - 1, a.second});
  }
  long long int ans = 0;
  for (int i = 0; i <= PQ.top().first; i++) {
    if (i & 1) {
      ans += MOD - box[PQ.top().second][i] * by[N * 2 - i * 2] % MOD *
                       rev[N - i] % MOD * power(rev[2], N - i, MOD) % MOD;
    } else {
      ans += box[PQ.top().second][i] * by[N * 2 - i * 2] % MOD * rev[N - i] %
             MOD * power(rev[2], N - i, MOD) % MOD;
    }
  }
  cout << ans % MOD << endl;
}