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

// Author - Rahil Malhotra
#include <bits/stdc++.h>
using namespace std;

template <typename T> void print(T t) { cout << t << endl; }
template <typename T, typename... Args> void print(T t, Args... args) {
  cout << t << " ";
  print(args...);
}

#define IOS                                                                    \\
  ios::sync_with_stdio(0);                                                     \\
  cin.tie(0);                                                                  \\
  cout.tie(0);
#define endl '\\n'
#define int long long
#define double long double

int mod = 998244353;
int md = 998244353;

inline void add(int &a, int b) {
  a += b;
  if (a >= md)
    a -= md;
}

inline void sub(int &a, int b) {
  a -= b;
  if (a < 0)
    a += md;
}

inline int mul(int a) { return a; }

template <typename... T> inline int mul(int a, T... b) {
  return (int)((long long)a * mul(b...) % md);
}

inline int power(int a, long long b) {
  int res = 1;
  while (b > 0) {
    if (b & 1) {
      res = mul(res, a);
    }
    a = mul(a, a);
    b >>= 1;
  }
  return res;
}

inline int inv(int a) {
  a %= md;
  if (a < 0)
    a += md;
  int b = md, u = 0, v = 1;
  while (a) {
    int t = b / a;
    b -= t * a;
    swap(a, b);
    u -= t * v;
    swap(u, v);
  }
  assert(b == 1);
  if (u < 0)
    u += md;
  return u;
}

namespace ntt {
int base = 1;
vector<int> roots = {0, 1};
vector<int> rev = {0, 1};
int max_base = -1;
int root = -1;

void init() {
  int tmp = md - 1;
  max_base = 0;
  while (tmp % 2 == 0) {
    tmp /= 2;
    max_base++;
  }
  root = 2;
  while (true) {
    if (power(root, 1 << max_base) == 1) {
      if (power(root, 1 << (max_base - 1)) != 1) {
        break;
      }
    }
    root++;
  }
}

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

void fft(vector<int> &a) {
  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 x = a[i + j];
        int y = mul(a[i + j + k], roots[j + k]);
        a[i + j] = x + y - md;
        if (a[i + j] < 0)
          a[i + j] += md;
        a[i + j + k] = x - y + md;
        if (a[i + j + k] >= md)
          a[i + j + k] -= md;
      }
    }
  }
}

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

vector<int> square(vector<int> a) { return multiply(a, a, 1); }
} // namespace ntt

int n;
map<int, int> mp;
int fact[200005];
int premul[200005];
int grp;
vector<int> v[200005];
vector<int> tree[700005];
int inver(int x) {
  int r, y;
  for (r = 1, y = mod - 2; y > 0; x = (x * x) % mod, y /= 2)
    if (y % 2 == 1)
      r = r * x % mod;
  return r;
}
int nCr(int n, int m) {
  if (n < m)
    return 0;
  return fact[n] * inver(fact[m]) % mod * inver(fact[n - m]) % mod;
}
void mulall(int i, int l, int r) {
  if (l == r) {
    tree[i] = v[l];
    return;
  }
  int mid = (l + r) / 2;
  mulall(i * 2, l, mid);
  mulall(i * 2 + 1, mid + 1, r);
  tree[i] = ntt::multiply(tree[i * 2], tree[i * 2 + 1]);
}
int32_t main() {
  IOS;
  cin >> n;
  premul[1] = 1;
  for (int i = 3; i <= 2 * n - 1; i++)
    premul[i] = (i * premul[i - 2]) % mod;
  fact[0] = 1;
  for (int i = 1; i <= 200001; i++)
    fact[i] = (i * fact[i - 1]) % mod;
  for (int i = 0; i < 2 * n; i++) {
    int a;
    cin >> a;
    mp[a]++;
  }
  grp = mp.size();
  int ctr = 0;
  for (auto i : mp) {
    v[ctr].push_back(1);
    int sz = i.second;
    int val = 1;
    for (int j = 1; j <= sz / 2; j++) {
      int a = nCr(sz, 2 * j);
      int arrange = premul[2 * j - 1];
      int val = (a * arrange) % mod;
      v[ctr].push_back(val);
    }
    ctr++;
  }
  // for(int i=0;i<grp;i++)
  // {
  //     for(int j:v[i])
  //         cout<<j<<" ";
  //     cout<<endl;
  // }
  mulall(1, 0, ctr - 1);
  vector<int> fin = tree[1];
  int ct = n;
  int ans = 0;
  int st = 0;
  for (auto i : fin) {
    if (st % 2 == 0) {
      int get = 0;
      if (ct == 0)
        get = i;
      else
        get = (premul[2 * ct - 1] * i) % mod;
      ans = (ans + get) % mod;
    } else {
      int get = 0;
      if (ct == 0)
        get = i;
      else
        get = (premul[2 * ct - 1] * i) % mod;
      ans = (ans - get + mod) % mod;
    }
    // cout<<st<<" "<<ct<<" "<<i<<" "<<ans<<endl;
    ct--;
    st++;
    // cout<<i<<" ";
  }
  cout << ans << endl;
}


Error: TLE

Fixed submission:

// Author - Rahil Malhotra
#include <bits/stdc++.h>
using namespace std;

template <typename T> void print(T t) { cout << t << endl; }
template <typename T, typename... Args> void print(T t, Args... args) {
  cout << t << " ";
  print(args...);
}

#define IOS                                                                    \\
  ios::sync_with_stdio(0);                                                     \\
  cin.tie(0);                                                                  \\
  cout.tie(0);
#define endl '\\n'
#define int long long
#define double long double

int mod = 998244353;
int md = 998244353;

inline void add(int &a, int b) {
  a += b;
  if (a >= md)
    a -= md;
}

inline void sub(int &a, int b) {
  a -= b;
  if (a < 0)
    a += md;
}

inline int mul(int a) { return a; }

template <typename... T> inline int mul(int a, T... b) {
  return (int)((long long)a * mul(b...) % md);
}

inline int power(int a, long long b) {
  int res = 1;
  while (b > 0) {
    if (b & 1) {
      res = mul(res, a);
    }
    a = mul(a, a);
    b >>= 1;
  }
  return res;
}

inline int inv(int a) {
  a %= md;
  if (a < 0)
    a += md;
  int b = md, u = 0, v = 1;
  while (a) {
    int t = b / a;
    b -= t * a;
    swap(a, b);
    u -= t * v;
    swap(u, v);
  }
  assert(b == 1);
  if (u < 0)
    u += md;
  return u;
}

namespace ntt {
int base = 1;
vector<int> roots = {0, 1};
vector<int> rev = {0, 1};
int max_base = -1;
int root = -1;

void init() {
  int tmp = md - 1;
  max_base = 0;
  while (tmp % 2 == 0) {
    tmp /= 2;
    max_base++;
  }
  root = 2;
  while (true) {
    if (power(root, 1 << max_base) == 1) {
      if (power(root, 1 << (max_base - 1)) != 1) {
        break;
      }
    }
    root++;
  }
}

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

void fft(vector<int> &a) {
  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 x = a[i + j];
        int y = mul(a[i + j + k], roots[j + k]);
        a[i + j] = x + y - md;
        if (a[i + j] < 0)
          a[i + j] += md;
        a[i + j + k] = x - y + md;
        if (a[i + j + k] >= md)
          a[i + j + k] -= md;
      }
    }
  }
}

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

vector<int> square(vector<int> a) { return multiply(a, a, 1); }
} // namespace ntt

int n;
map<int, int> mp;
int fact[200005];
int premul[200005];
int inver(int x) {
  int r, y;
  for (r = 1, y = mod - 2; y > 0; x = (x * x) % mod, y /= 2)
    if (y % 2 == 1)
      r = r * x % mod;
  return r;
}
int nCr(int n, int m) {
  if (n < m)
    return 0;
  return fact[n] * inver(fact[m]) % mod * inver(fact[n - m]) % mod;
}
int32_t main() {
  IOS;
  cin >> n;
  premul[1] = 1;
  for (int i = 3; i <= 2 * n - 1; i++)
    premul[i] = (i * premul[i - 2]) % mod;
  fact[0] = 1;
  for (int i = 1; i <= 200001; i++)
    fact[i] = (i * fact[i - 1]) % mod;
  for (int i = 0; i < 2 * n; i++) {
    int a;
    cin >> a;
    mp[a]++;
  }
  int grp = mp.size();
  vector<int> v[grp];
  int ctr = 0;
  for (auto i : mp) {
    v[ctr].push_back(1);
    int sz = i.second;
    int val = 1;
    for (int j = 1; j <= sz / 2; j++) {
      int a = nCr(sz, 2 * j);
      int arrange = premul[2 * j - 1];
      int val = (a * arrange) % mod;
      // val=(val*nCr(sz-j+2,2))%mod;
      v[ctr].push_back(val);
    }
    ctr++;
  }
  // for(int i=0;i<grp;i++)
  // {
  //     for(int j:v[i])
  //         cout<<j<<" ";
  //     cout<<endl;
  // }
  vector<int> fin;
  fin.push_back(1);
  for (int i = 0; i < grp; i++)
    fin = ntt::multiply(fin, v[i]);

  int ct = n;
  int ans = 0;
  int st = 0;
  for (auto i : fin) {
    if (st % 2 == 0) {
      int get = 0;
      if (ct == 0)
        get = i;
      else
        get = (premul[2 * ct - 1] * i) % mod;
      ans = (ans + get) % mod;
    } else {
      int get = 0;
      if (ct == 0)
        get = i;
      else
        get = (premul[2 * ct - 1] * i) % mod;
      ans = (ans - get + mod) % mod;
    }
    // cout<<st<<" "<<ct<<" "<<i<<" "<<ans<<endl;
    ct--;
    st++;
    // cout<<i<<" ";
  }
  cout << ans << endl;
}