Problem p02539 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<ll, ll> p_ll;

template <class T> void debug(T itr1, T itr2) {
  auto now = itr1;
  while (now < itr2) {
    cout << *now << " ";
    now++;
  }
  cout << endl;
}
#define repr(i, from, to) for (ll i = (ll)from; i < (ll)to; i++)
#define all(vec) vec.begin(), vec.end()
#define rep(i, N) repr(i, 0, N)
#define per(i, N) for (ll i = (ll)N - 1; i >= 0; i--)

const ll MOD = 998244353;
const ll LLINF = pow(2, 61) - 1;
const ll INF = pow(2, 30) - 1;

vector<ll> fac;
void c_fac(ll x = pow(10, 6) + 10) {
  fac.resize(x, true);
  rep(i, x) fac[i] = i ? (fac[i - 1] * i) % MOD : 1;
}
ll inv(ll a, ll m = MOD) {
  ll b = m, x = 1, y = 0;
  while (b != 0) {
    ll d = a / b;
    a -= b * d;
    swap(a, b);
    x -= y * d;
    swap(x, y);
  }
  return (x + m) % m;
}
ll nck(ll n, ll k) { return fac[n] * inv(fac[k] * fac[n - k] % MOD) % MOD; }
ll modpow(ll x, ll p) {
  ll result = 1, now = 1, pm = x;
  while (now <= p) {
    if (p & now) {
      result = result * pm % MOD;
    }
    now *= 2;
    pm = pm * pm % MOD;
  }
  return result;
}
ll gcd(ll a, ll b) {
  if (a < b)
    swap(a, b);
  return b == 0 ? a : gcd(b, a % b);
}
ll lcm(ll a, ll b) { return a / gcd(a, b) * b; }

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------

struct FastNumberTheoreticTransform {

  ll size = 1, size_x12, root;
  vector<ll> x1, x2, theta;

  FastNumberTheoreticTransform(ll s = 10) {
    while (size < s)
      size *= 2;
    root = modpow(3, MOD / size);
    x1.resize(size);
    x2.resize(size);
    theta.resize(size);
    rep(i, size) theta[i] = i == 0 ? 1 : theta[i - 1] * root % MOD;
  }

  void set(vector<ll> &v1, vector<ll> &v2) {
    size_x12 = v1.size() + v2.size() - 1;
    x1 = v1;
    x2 = v2;
  }

  vector<ll> convolution(vector<ll> &x, bool rev, ll s, ll pos = 0) {
    if (s == 1)
      return {x[pos]};
    vector<ll> ex = convolution(x, rev, s / 2, pos),
               ox = convolution(x, rev, s / 2, pos + size / s);
    vector<ll> result(s);
    rep(i, s) result[i] =
        (ex[i % (s / 2)] + theta[size / s * i] * ox[i % (s / 2)]) % MOD;
    if (rev && s == size) {
      reverse(result.begin() + 1, result.end());
      ll invs = inv(size);
      for (auto &x : result)
        x = x * invs % MOD;
    }
    return result;
  };

  vector<ll> calc(vector<ll> &v1, vector<ll> &v2) {
    set(v1, v2);
    vector<ll> cx1 = convolution(x1, false, size),
               cx2 = convolution(x2, false, size);
    vector<ll> cx12(size);
    rep(i, size) cx12[i] = cx1[i] * cx2[i] % MOD;
    vector<ll> x12 = convolution(cx12, true, size);
    vector<ll> result(size_x12);
    copy(x12.begin(), x12.begin() + size_x12, result.begin());
    return result;
  }
};

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------

int main() {
  ll N;
  cin >> N;
  N *= 2;
  ll h[N];
  rep(i, N) cin >> h[i];
  sort(h, h + N);
  map<ll, ll> m;
  rep(i, N) m[h[i]]++;

  for (auto x : m) {
    if (x.second > N / 2) {
      cout << 0 << endl;
      return 0;
    }
  }

  c_fac();
  deque<vector<ll>> dq;
  for (auto x : m) {
    ll l = x.second / 2 + 1;
    vector<ll> count(l);
    rep(i, l) count[i] = i == 0
                             ? 1
                             : count[i - 1] * nck(x.second - (i - 1) * 2, 2) %
                                   MOD * inv(i) % MOD;
    if (count.size() >= 2)
      dq.push_back(count);
  }

  while (dq.size() >= 2) {
    FastNumberTheoreticTransform FNTT(dq[0].size() + dq[1].size());
    vector<ll> v = FNTT.calc(dq[0], dq[1]);
    dq.pop_front();
    dq.pop_front();
    dq.push_back(v);
  }
  vector<ll> mul;
  if (dq.size())
    mul = dq[0];
  else
    mul = {1};
  vector<ll> num(N);
  rep(i, N) num[i] =
      i == 0 ? 1 : num[i - 1] * nck(i * 2, 2) % MOD * inv(i) % MOD;
  // debug(all(mul)); debug(all(num));

  ll result = 0;
  rep(i, mul.size()) result =
      i % 2 == 0 ? (result + num[N / 2 - i] * mul[i] % MOD) % MOD
                 : (result - num[N / 2 - i] * mul[i] % MOD + MOD) % MOD;
  cout << result << endl;
  return 0;
}

Error: TLE

Fixed submission:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<ll, ll> p_ll;

template <class T> void debug(T itr1, T itr2) {
  auto now = itr1;
  while (now < itr2) {
    cout << *now << " ";
    now++;
  }
  cout << endl;
}
#define repr(i, from, to) for (ll i = (ll)from; i < (ll)to; i++)
#define all(vec) vec.begin(), vec.end()
#define rep(i, N) repr(i, 0, N)
#define per(i, N) for (ll i = (ll)N - 1; i >= 0; i--)

const ll MOD = 998244353;
const ll LLINF = pow(2, 61) - 1;
const ll INF = pow(2, 30) - 1;

vector<ll> fac;
void c_fac(ll x = pow(10, 6) + 10) {
  fac.resize(x, true);
  rep(i, x) fac[i] = i ? (fac[i - 1] * i) % MOD : 1;
}
ll inv(ll a, ll m = MOD) {
  ll b = m, x = 1, y = 0;
  while (b != 0) {
    ll d = a / b;
    a -= b * d;
    swap(a, b);
    x -= y * d;
    swap(x, y);
  }
  return (x + m) % m;
}
ll nck(ll n, ll k) { return fac[n] * inv(fac[k] * fac[n - k] % MOD) % MOD; }
ll modpow(ll x, ll p) {
  ll result = 1, now = 1, pm = x;
  while (now <= p) {
    if (p & now) {
      result = result * pm % MOD;
    }
    now *= 2;
    pm = pm * pm % MOD;
  }
  return result;
}
ll gcd(ll a, ll b) {
  if (a < b)
    swap(a, b);
  return b == 0 ? a : gcd(b, a % b);
}
ll lcm(ll a, ll b) { return a / gcd(a, b) * b; }

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------

struct FastNumberTheoreticTransform {

  ll size = 1, size_x12, root;
  vector<ll> x1, x2, theta;

  FastNumberTheoreticTransform(ll s = 10) {
    while (size < s)
      size *= 2;
    root = modpow(3, MOD / size);
    x1.resize(size);
    x2.resize(size);
    theta.resize(size);
    rep(i, size) theta[i] = i == 0 ? 1 : theta[i - 1] * root % MOD;
  }

  void set(vector<ll> &v1, vector<ll> &v2) {
    size_x12 = v1.size() + v2.size() - 1;
    x1 = v1;
    x2 = v2;
  }

  vector<ll> convolution(vector<ll> &x, bool rev, ll s, ll pos = 0) {
    if (s == 1)
      return {x[pos]};
    vector<ll> ex = convolution(x, rev, s / 2, pos),
               ox = convolution(x, rev, s / 2, pos + size / s);
    vector<ll> result(s);
    rep(i, s) result[i] =
        (ex[i % (s / 2)] + theta[size / s * i] * ox[i % (s / 2)]) % MOD;
    if (rev && s == size) {
      reverse(result.begin() + 1, result.end());
      ll invs = inv(size);
      for (auto &x : result)
        x = x * invs % MOD;
    }
    return result;
  };

  vector<ll> calc(vector<ll> &v1, vector<ll> &v2) {
    set(v1, v2);
    vector<ll> cx1 = convolution(x1, false, size),
               cx2 = convolution(x2, false, size);
    vector<ll> cx12(size);
    rep(i, size) cx12[i] = cx1[i] * cx2[i] % MOD;
    vector<ll> x12 = convolution(cx12, true, size);
    vector<ll> result(size_x12);
    copy(x12.begin(), x12.begin() + size_x12, result.begin());
    return result;
  }
};

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------

int main() {
  ll N;
  cin >> N;
  N *= 2;
  ll h[N];
  rep(i, N) cin >> h[i];
  sort(h, h + N);
  map<ll, ll> m;
  rep(i, N) m[h[i]]++;

  c_fac();
  vector<vector<ll>> fnc;
  for (auto x : m) {
    if (x.second > N / 2) {
      cout << 0 << endl;
      return 0;
    }
  }
  for (auto x : m) {
    ll l = x.second / 2 + 1;
    vector<ll> count(l);
    rep(i, l) count[i] = i == 0
                             ? 1
                             : count[i - 1] * nck(x.second - (i - 1) * 2, 2) %
                                   MOD * inv(i) % MOD;
    if (count.size() >= 2)
      fnc.push_back(count);
  }

  vector<ll> mul = {1};
  for (auto x : fnc) {
    FastNumberTheoreticTransform FNTT(mul.size() + x.size());
    mul = FNTT.calc(mul, x);
  }
  vector<ll> num(N);
  rep(i, N) num[i] =
      i == 0 ? 1 : num[i - 1] * nck(i * 2, 2) % MOD * inv(i) % MOD;
  // debug(all(mul)); debug(all(num));

  ll result = 0;
  rep(i, mul.size()) result =
      i % 2 == 0 ? (result + num[N / 2 - i] * mul[i] % MOD) % MOD
                 : (result - num[N / 2 - i] * mul[i] % MOD + MOD) % MOD;
  cout << result << endl;
  return 0;
}