Problem p02539 (C++)

Buggy submission (status: Time Limit Exceeded):
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); i++)
using namespace std;
typedef long long ll;
typedef pair<int, int> P;

const int MOD = 998244353;
const int INF = 0x3f3f3f3f;
const ll INFL = 0x3f3f3f3f3f3f3f3f;

/*
#include <atcoder/segtree>
using namespace atcoder;
*/

ll ppow(ll a, ll b) {
  a %= MOD;
  ll res = 1;
  while (b) {
    if (b & 1)
      res = (res * a) % MOD;
    a = (a * a) % MOD;
    b >>= 1;
  }
  return res;
}

class Fact {
  vector<ll> fact;
  vector<ll> inv;

public:
  Fact() {}
  Fact(int n) {
    n = n * 2 + 10;
    fact = inv = vector<ll>(n);
    fact[0] = inv[0] = 1;
    for (int i = 1; i < n; i++) {
      fact[i] = (fact[i - 1] * i) % MOD;
    }
    inv[n - 1] = ppow(fact[n - 1], MOD - 2);
    for (int i = n - 2; i >= 0; i--) {
      inv[i] = (inv[i + 1] * (i + 1)) % MOD;
    }
  }
  ll get(int n) { return fact[n]; }
  ll get_inv(int n) { return inv[n]; }
  ll nPr(int n, int r) { return fact[n] * inv[n - r] % MOD; }
  ll nCr(int n, int r) { return nPr(n, r) * inv[r] % MOD; }
  ll nrP(int n, int r) { return nPr(n + r, n); }
  ll nrC(int n, int r) { return nCr(n + r, n); }
};

const int r = 3;

void dft(vector<ll> &f, bool inv = false) {
  int n = f.size();
  rep(i, n) {
    int b = 31 - __builtin_clz(n);
    int j = 0;
    rep(k, b) {
      if (i >> k & 1)
        j |= 1 << (b - k - 1);
    }
    if (i < j)
      swap(f[i], f[j]);
  }
  for (int i = 2; i <= n; i <<= 1) {
    ll w = ppow(r, (MOD - 1) / i);
    if (inv)
      w = ppow(w, MOD - 2);
    for (int k = 0; k < n; k += i) {
      ll x = 1;
      rep(j, i / 2) {
        ll t = x * f[k + j + i / 2] % MOD, u = f[k + j];
        f[k + j] = (u + t) % MOD;
        f[k + j + i / 2] = (u + MOD - t) % MOD;
        (x *= w) %= MOD;
      }
    }
  }
  if (inv) {
    ll n_inv = ppow(n, MOD - 2);
    rep(i, n)(f[i] *= n_inv) %= MOD;
  }
}

vector<ll> multiply(vector<ll> A, vector<ll> B) {
  int m = A.size() + B.size();
  int N = 1;
  while (N < A.size() + B.size())
    N <<= 1;
  A.resize(N);
  B.resize(N);
  dft(A, 0);
  dft(B, 0);
  vector<ll> f(N);
  rep(i, N) f[i] = A[i] * B[i] % MOD;
  dft(f, 1);
  f.erase(f.begin() + m - 1, f.end());
  return f;
}

int h[200000];
int d[200000];

int main() {
  int n;
  cin >> n;
  rep(i, 2 * n) {
    scanf("%d", &h[i]);
    d[h[i]]++;
  }
  Fact fac(2 * n);
  vector<ll> v(1);
  v[0] = 1;
  vector<vector<ll>> bs;
  bs.push_back(v);
  rep(i, 100001) {
    if (d[i] == 0)
      continue;
    vector<ll> B;
    rep(j, d[i] / 2 + 1) {
      ll X = fac.nCr(d[i], j * 2) * fac.get(2 * j) % MOD * fac.get_inv(j) % MOD;
      B.push_back(X);
    }
    bs.push_back(B);
    v = multiply(v, B);
  }
  while (bs.size() > 1) {
    vector<vector<ll>> nbs;
    for (int i = 0; i < bs.size(); i += 2) {
      if (i + 1 >= bs.size())
        nbs.push_back(bs[i]);
      else {
        nbs.push_back(multiply(bs[i], bs[i + 1]));
      }
    }
    bs = nbs;
  }
  v = bs[0];
  ll U = 0;
  for (ll i = 0; i <= min(n, (int)v.size() - 1); i++) {
    ll X = v[i] * fac.nCr(n, i) % MOD * fac.get(i) % MOD *
           fac.get(2 * n - 2 * i) % MOD;
    //~ cout<<"X: "<<X<<endl;
    if (i % 2 == 0)
      (U += X) %= MOD;
    else
      (U += MOD - X) %= MOD;
  }
  //~ cout<<U<<endl;
  ll ans = U * fac.get_inv(n) % MOD * ppow(ppow(2, n), MOD - 2) % MOD;
  cout << ans << endl;
}

Fixed submission:
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); i++)
using namespace std;
typedef long long ll;
typedef pair<int, int> P;

const int MOD = 998244353;
const int INF = 0x3f3f3f3f;
const ll INFL = 0x3f3f3f3f3f3f3f3f;

/*
#include <atcoder/segtree>
using namespace atcoder;
*/

ll ppow(ll a, ll b) {
  a %= MOD;
  ll res = 1;
  while (b) {
    if (b & 1)
      res = (res * a) % MOD;
    a = (a * a) % MOD;
    b >>= 1;
  }
  return res;
}

class Fact {
  vector<ll> fact;
  vector<ll> inv;

public:
  Fact() {}
  Fact(int n) {
    n = n * 2 + 10;
    fact = inv = vector<ll>(n);
    fact[0] = inv[0] = 1;
    for (int i = 1; i < n; i++) {
      fact[i] = (fact[i - 1] * i) % MOD;
    }
    inv[n - 1] = ppow(fact[n - 1], MOD - 2);
    for (int i = n - 2; i >= 0; i--) {
      inv[i] = (inv[i + 1] * (i + 1)) % MOD;
    }
  }
  ll get(int n) { return fact[n]; }
  ll get_inv(int n) { return inv[n]; }
  ll nPr(int n, int r) { return fact[n] * inv[n - r] % MOD; }
  ll nCr(int n, int r) { return nPr(n, r) * inv[r] % MOD; }
  ll nrP(int n, int r) { return nPr(n + r, n); }
  ll nrC(int n, int r) { return nCr(n + r, n); }
};

const int r = 3;

void dft(vector<ll> &f, bool inv = false) {
  int n = f.size();
  rep(i, n) {
    int b = 31 - __builtin_clz(n);
    int j = 0;
    rep(k, b) {
      if (i >> k & 1)
        j |= 1 << (b - k - 1);
    }
    if (i < j)
      swap(f[i], f[j]);
  }
  for (int i = 2; i <= n; i <<= 1) {
    ll w = ppow(r, (MOD - 1) / i);
    if (inv)
      w = ppow(w, MOD - 2);
    for (int k = 0; k < n; k += i) {
      ll x = 1;
      rep(j, i / 2) {
        ll t = x * f[k + j + i / 2] % MOD, u = f[k + j];
        f[k + j] = (u + t) % MOD;
        f[k + j + i / 2] = (u + MOD - t) % MOD;
        (x *= w) %= MOD;
      }
    }
  }
  if (inv) {
    ll n_inv = ppow(n, MOD - 2);
    rep(i, n)(f[i] *= n_inv) %= MOD;
  }
}

vector<ll> multiply(vector<ll> A, vector<ll> B) {
  int m = A.size() + B.size();
  int N = 1;
  while (N < A.size() + B.size())
    N <<= 1;
  A.resize(N);
  B.resize(N);
  dft(A, 0);
  dft(B, 0);
  vector<ll> f(N);
  rep(i, N) f[i] = A[i] * B[i] % MOD;
  dft(f, 1);
  f.erase(f.begin() + m - 1, f.end());
  return f;
}

int h[200000];
int d[200000];

int main() {
  int n;
  cin >> n;
  rep(i, 2 * n) {
    scanf("%d", &h[i]);
    d[h[i]]++;
  }
  Fact fac(2 * n);
  vector<ll> v(1);
  v[0] = 1;
  vector<vector<ll>> bs;
  bs.push_back(v);
  rep(i, 100001) {
    if (d[i] == 0)
      continue;
    vector<ll> B;
    rep(j, d[i] / 2 + 1) {
      ll X = fac.nCr(d[i], j * 2) * fac.get(2 * j) % MOD * fac.get_inv(j) % MOD;
      B.push_back(X);
    }
    bs.push_back(B);
  }
  while (bs.size() > 1) {
    vector<vector<ll>> nbs;
    for (int i = 0; i < bs.size(); i += 2) {
      if (i + 1 >= bs.size())
        nbs.push_back(bs[i]);
      else {
        nbs.push_back(multiply(bs[i], bs[i + 1]));
      }
    }
    bs = nbs;
  }
  v = bs[0];
  ll U = 0;
  for (ll i = 0; i <= min(n, (int)v.size() - 1); i++) {
    ll X = v[i] * fac.nCr(n, i) % MOD * fac.get(i) % MOD *
           fac.get(2 * n - 2 * i) % MOD;
    //~ cout<<"X: "<<X<<endl;
    if (i % 2 == 0)
      (U += X) %= MOD;
    else
      (U += MOD - X) %= MOD;
  }
  //~ cout<<U<<endl;
  ll ans = U * fac.get_inv(n) % MOD * ppow(ppow(2, n), MOD - 2) % MOD;
  cout << ans << endl;
}