Problem p02539 (C++)

Buggy submission (status: Runtime Error):
#include <iostream>
using i64 = long long;
template <i64 M> struct modint {
  i64 a;
  constexpr modint(const i64 x = 0) : a((x % M + M) % M) {}
  constexpr i64 value() const { return a; }
  constexpr modint inv() const { return this->pow(M - 2); }
  constexpr modint pow(i64 r) const {
    modint ans(1);
    modint aa = *this;
    while (r) {
      if (r & 1)
        ans *= aa;
      aa *= aa;
      r >>= 1;
    }
    return ans;
  }
  constexpr modint &operator=(const i64 r) {
    a = (r % M + M) % M;
    return *this;
  }
  constexpr modint &operator+=(const modint r) {
    a += r.a;
    if (a >= M)
      a -= M;
    return *this;
  }
  constexpr modint &operator-=(const modint r) {
    a -= r.a;
    if (a < 0)
      a += M;
    return *this;
  }
  constexpr modint &operator*=(const modint r) {
    a = a * r.a % M;
    return *this;
  }
  constexpr modint &operator/=(const modint r) {
    (*this) *= r.inv();
    return *this;
  }
  constexpr modint operator+(const modint r) const {
    return modint(*this) += r;
  }
  constexpr modint operator-(const modint r) const {
    return modint(*this) -= r;
  }
  constexpr modint operator*(const modint r) const {
    return modint(*this) *= r;
  }
  constexpr modint operator/(const modint r) const {
    return modint(*this) /= r;
  }
  constexpr bool operator==(const modint r) const {
    return this->value() == r.value();
  }
  constexpr bool operator!=(const modint r) const {
    return this->value() != r.value();
  }
};

template <const i64 M>
std::ostream &operator<<(std::ostream &os, const modint<M> &m) {
  os << m.value();
  return os;
}

#include <vector>
using namespace std;
constexpr i64 NTT_PRIMES[][2] = {
    {1224736769, 3}, // 2^24 * 73 + 1,
    {1053818881, 7}, // 2^20 * 3 * 5 * 67 + 1
    {1051721729, 6}, // 2^20 * 17 * 59 + 1
    {1045430273, 3}, // 2^20 * 997 + 1
    {1012924417, 5}, // 2^21 * 3 * 7 * 23 + 1
    {1007681537, 3}, // 2^20 * 31^2 + 1
    {1004535809, 3}, // 2^21 * 479 + 1
    {998244353, 3},  // 2^23 * 7 * 17 + 1
    {985661441, 3},  // 2^22 * 5 * 47 + 1
    {976224257, 3},  // 2^20 * 7^2 * 19 + 1
    {975175681, 17}, // 2^21 * 3 * 5 * 31 + 1
    {962592769, 7},  // 2^21 * 3^3 * 17 + 1
    {950009857, 7},  // 2^21 * 4 * 151 + 1
    {943718401, 7},  // 2^22 * 3^2 * 5^2 + 1
    {935329793, 3},  // 2^22 * 223 + 1
    {924844033, 5},  // 2^21 * 3^2 * 7^2 + 1
    {469762049, 3},  // 2^26 * 7 + 1
    {167772161, 3},  // 2^25 * 5 + 1
};

template <const i64 mod, const i64 primitive>
vector<modint<mod>> number_theoretic_transform(vector<modint<mod>> a) {
  i64 n = a.size();
  for (i64 s = n >> 1; s >= 1; s >>= 1) {
    modint<mod> zeta = modint<mod>(primitive).pow((mod - 1) / (s << 1));
    for (i64 i = 0; i < n; i += (s << 1)) {
      modint<mod> zi = 1;
      for (i64 j = 0; j < s; j++) {
        modint<mod> t = a[i + j] - a[s + i + j];
        a[i + j] += a[s + i + j];
        a[s + i + j] = t * zi;
        zi = zi * zeta;
      }
    }
  }
  return a;
}

template <const i64 mod, const i64 primitive>
vector<modint<mod>> inverse_number_theoretic_transform(vector<modint<mod>> a) {
  i64 n = a.size();
  for (i64 s = 1; s < n; s <<= 1) {
    modint<mod> zeta =
        modint<mod>(primitive).pow((mod - 1) / (s << 1)).pow(mod - 2);
    for (i64 i = 0; i < n; i += (s << 1)) {
      modint<mod> zi = 1;
      for (i64 j = 0; j < s; j++) {
        modint<mod> t = a[s + i + j] * zi;
        a[s + i + j] = a[i + j] - t;
        a[i + j] = a[i + j] + t;
        zi = zi * zeta;
      }
    }
  }
  auto inv_n = modint<mod>(n).pow(mod - 2);
  for (int i = 0; i < n; i++)
    a[i] *= inv_n;
  return a;
}

template <const i64 mod, const i64 primitive> struct fps_ntt_multiply {
  using fps_type = modint<mod>;
  using conv_type = modint<mod>;
  static std::vector<conv_type> dft(std::vector<fps_type> arr) {
    return number_theoretic_transform<mod, primitive>(std::move(arr));
  }
  static std::vector<fps_type> idft(std::vector<conv_type> arr) {
    return inverse_number_theoretic_transform<mod, primitive>(std::move(arr));
  }
  static std::vector<conv_type> multiply(std::vector<conv_type> a,
                                         std::vector<conv_type> b) {
    for (int i = 0; i < a.size(); i++)
      a[i] *= b[i];
    return a;
  }
};

template <class T, class fps_multiply> struct FPS {
  std::vector<T> coef;

  static std::size_t bound_pow2(std::size_t sz) {
    return 1ll << (__lg(sz - 1) + 1);
  }

  FPS(const std::vector<T> &arr) : coef(arr) {}
  size_t size() const { return coef.size(); }
  void bound_resize() { this->coef.resize(bound_pow2(this->size())); }
  void resize_zero() {
    while (coef.size() > 1 && coef.back() == T(0)) {
      coef.pop_back();
    }
  }
  T operator[](int i) const {
    if (i < coef.size())
      return coef[i];
    else
      return T();
  }
  T &operator[](int i) { return coef[i]; }
  FPS pre(int n) const {
    std::vector<T> nex(n);
    for (int i = 0; i < coef.size() && i < n; i++)
      nex[i] = coef[i];
    return FPS(nex);
  }

  // F(0) must not be 0
  FPS inv() const {
    FPS g = FPS(std::vector<T>{T(1) / (*this)[0]});
    this->bound_resize();
    i64 n = this->size();
    for (int i = 1; i < n; i <<= 1) {
      g = g.pre(i << 1);
      auto gdft = fps_multiply::dft(g.coef);
      auto e = fps_multiply::idft(fps_multiply::multiply(
          fps_multiply::dft(this->pre(i << 1).coef), gdft));
      for (int j = 0; j < i; j++) {
        e[j] = T(0);
        e[j + i] = e[j + i] * T(-1);
      }
      auto f = fps_multiply::idft(
          fps_multiply::multiply(fps_multiply::dft(e), std::move(gdft)));
      for (int j = 0; j < i; j++) {
        f[j] = g[j];
      }
      g.coef = std::move(f);
    }
    return g.pre(n);
  }

  FPS diff() const {
    FPS res(vector<T>(this->size() - 1, T(0)));
    for (i64 i = 1; i < this->size(); i++)
      res[i - 1] = coef[i] * T(i);
    return res;
  }

  FPS integral() const {
    FPS res(vector<T>(this->size() + 1, T(0)));
    for (i64 i = 0; i < this->size(); i++)
      res[i + 1] = coef[i] / T(i + 1);
    return res;
  }

  // F(0) must be 0
  FPS log() const {
    return (this->diff() * this->inv()).integral().pre(this->size());
  }

  FPS exp() const {
    FPS f(vector<T>{T(1)});
    FPS g = *this;
    g.bound_resize();
    g[0] += T(1);
    for (i64 i = 1; i < size(); i <<= 1) {
      f = (f * (g.pre(i << 1) - f.pre(i << 1).log())).pre(i << 1);
    }
    return f;
  }

  FPS operator+(const FPS &rhs) {
    i64 n = std::max(this->size(), rhs.size());
    std::vector<T> ans(n);
    for (int i = 0; i < n; i++)
      ans[i] = (*this)[i] + rhs[i];
    return FPS(ans);
  }
  FPS operator-(const FPS &rhs) {
    i64 n = std::max(this->size(), rhs.size());
    std::vector<T> ans(n);
    for (int i = 0; i < n; i++)
      ans[i] = (*this)[i] - rhs[i];
    return FPS(ans);
  }
  FPS operator*(const FPS &rhs) {
    i64 m = this->size() + rhs.size() - 1;
    i64 n = bound_pow2(m);
    auto res = fps_multiply::idft(
        fps_multiply::multiply(fps_multiply::dft(this->pre(n).coef),
                               fps_multiply::dft(rhs.pre(n).coef)));
    res.resize(m);
    return res;
  }

  bool operator<(const FPS &rhs) const { return this->size() < rhs.size(); }
  bool operator>(const FPS &rhs) const { return this->size() > rhs.size(); }
};

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define rep(i, s, e) for (i64(i) = (s); (i) < (e); (i)++)
#define all(x) x.begin(), x.end()
#define STRINGIFY(n) #n
#define TOSTRING(n) STRINGIFY(n)
#define PREFIX "#" TOSTRING(__LINE__) "| "
#define debug(x)                                                               \
  { std::cout << PREFIX << #x << " = " << x << std::endl; }

std::ostream &output_indent(std::ostream &os, int ind) {
  for (int i = 0; i < ind; i++)
    os << " ";
  return os;
}

template <class S, class T>
std::ostream &operator<<(std::ostream &os, const std::pair<S, T> &p);
template <class T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v);

template <class S, class T>
std::ostream &operator<<(std::ostream &os, const std::pair<S, T> &p) {
  return (os << "(" << p.first << ", " << p.second << ")");
}
template <class T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v) {
  os << "[";
  for (int i = 0; i < v.size(); i++)
    os << v[i] << ", ";
  return (os << "]");
}

template <class T> static inline std::vector<T> ndvec(size_t &&n, T val) {
  return std::vector<T>(n, std::forward<T>(val));
}
template <class... Tail> static inline auto ndvec(size_t &&n, Tail &&...tail) {
  return std::vector<decltype(ndvec(std::forward<Tail>(tail)...))>(
      n, ndvec(std::forward<Tail>(tail)...));
}
template <class Cond> struct chain {
  Cond cond;
  chain(Cond cond) : cond(cond) {}
  template <class T> bool operator()(T &a, const T &b) const {
    if (cond(a, b)) {
      a = b;
      return true;
    }
    return false;
  }
};
template <class Cond> chain<Cond> make_chain(Cond cond) {
  return chain<Cond>(cond);
}

#include <tuple>
#include <vector>
using i64 = long long;

template <class T>
std::tuple<std::vector<T>, std::vector<T>, std::vector<T>>
build_factorial(int N) {
  std::vector<T> fact(N);
  std::vector<T> finv(N);
  std::vector<T> inv(N);
  fact[0] = T(1);
  for (int i = 1; i < N; i++) {
    fact[i] = fact[i - 1] * T(i);
  }
  finv[N - 1] = T(1) / fact[N - 1];
  for (int i = N - 1; i-- > 0;) {
    finv[i] = finv[i + 1] * T(i + 1);
  }
  for (int i = 0; i < N; i++) {
    inv[i] = fact[i - 1] * finv[i];
  }
  return std::make_tuple(std::move(fact), std::move(finv), std::move(inv));
}

using fp = modint<998244353>;
using fps = FPS<fp, fps_ntt_multiply<998244353, 3>>;

int main() {
  i64 N;
  cin >> N;
  vector<i64> cnt(101010);
  rep(i, 0, N * 2) {
    i64 a;
    cin >> a;
    cnt[a - 1]++;
  }

  auto [fact, finv, inv] = build_factorial<fp>(101010);
  fps meth(vector<fp>{fp(1)});

  vector<fp> setting;

  {
    fp now(1);
    setting.push_back(now);
    rep(i, 1, N + 1) {
      now *= fact[i * 2] * finv[i * 2 - 2] * finv[2];
      setting.push_back(now);
    }
  }

  priority_queue<fps, vector<fps>, greater<fps>> que;
  rep(x, 0, 101010) {
    if (cnt[x] <= 1)
      continue;
    vector<fp> vec;
    i64 c = cnt[x];
    for (i64 i = 0; i * 2 <= c; i++) {
      vec.push_back(fact[c] * finv[i * 2] * finv[c - i * 2] * setting[i] *
                    finv[i]);
    }
    que.push(fps(vec));
  }

  while (que.size() > 1) {
    auto f = que.top();
    que.pop();
    auto g = que.top();
    que.pop();
    que.push(f * g);
  }
  meth = que.top();
  fp ans(0);
  rep(i, 0, meth.size()) {
    if (i > N)
      break;
    fp res = meth[i] * setting[N - i] * finv[N - i];
    if (i % 2 == 0) {
      ans += res;
    } else {
      ans -= res;
    }
  }
  cout << ans.value() << endl;
}


Fixed submission:
#include <iostream>
using i64 = long long;
template <i64 M> struct modint {
  i64 a;
  constexpr modint(const i64 x = 0) : a((x % M + M) % M) {}
  constexpr i64 value() const { return a; }
  constexpr modint inv() const { return this->pow(M - 2); }
  constexpr modint pow(i64 r) const {
    modint ans(1);
    modint aa = *this;
    while (r) {
      if (r & 1)
        ans *= aa;
      aa *= aa;
      r >>= 1;
    }
    return ans;
  }
  constexpr modint &operator=(const i64 r) {
    a = (r % M + M) % M;
    return *this;
  }
  constexpr modint &operator+=(const modint r) {
    a += r.a;
    if (a >= M)
      a -= M;
    return *this;
  }
  constexpr modint &operator-=(const modint r) {
    a -= r.a;
    if (a < 0)
      a += M;
    return *this;
  }
  constexpr modint &operator*=(const modint r) {
    a = a * r.a % M;
    return *this;
  }
  constexpr modint &operator/=(const modint r) {
    (*this) *= r.inv();
    return *this;
  }
  constexpr modint operator+(const modint r) const {
    return modint(*this) += r;
  }
  constexpr modint operator-(const modint r) const {
    return modint(*this) -= r;
  }
  constexpr modint operator*(const modint r) const {
    return modint(*this) *= r;
  }
  constexpr modint operator/(const modint r) const {
    return modint(*this) /= r;
  }
  constexpr bool operator==(const modint r) const {
    return this->value() == r.value();
  }
  constexpr bool operator!=(const modint r) const {
    return this->value() != r.value();
  }
};

template <const i64 M>
std::ostream &operator<<(std::ostream &os, const modint<M> &m) {
  os << m.value();
  return os;
}

#include <vector>
using namespace std;
constexpr i64 NTT_PRIMES[][2] = {
    {1224736769, 3}, // 2^24 * 73 + 1,
    {1053818881, 7}, // 2^20 * 3 * 5 * 67 + 1
    {1051721729, 6}, // 2^20 * 17 * 59 + 1
    {1045430273, 3}, // 2^20 * 997 + 1
    {1012924417, 5}, // 2^21 * 3 * 7 * 23 + 1
    {1007681537, 3}, // 2^20 * 31^2 + 1
    {1004535809, 3}, // 2^21 * 479 + 1
    {998244353, 3},  // 2^23 * 7 * 17 + 1
    {985661441, 3},  // 2^22 * 5 * 47 + 1
    {976224257, 3},  // 2^20 * 7^2 * 19 + 1
    {975175681, 17}, // 2^21 * 3 * 5 * 31 + 1
    {962592769, 7},  // 2^21 * 3^3 * 17 + 1
    {950009857, 7},  // 2^21 * 4 * 151 + 1
    {943718401, 7},  // 2^22 * 3^2 * 5^2 + 1
    {935329793, 3},  // 2^22 * 223 + 1
    {924844033, 5},  // 2^21 * 3^2 * 7^2 + 1
    {469762049, 3},  // 2^26 * 7 + 1
    {167772161, 3},  // 2^25 * 5 + 1
};

template <const i64 mod, const i64 primitive>
vector<modint<mod>> number_theoretic_transform(vector<modint<mod>> a) {
  i64 n = a.size();
  for (i64 s = n >> 1; s >= 1; s >>= 1) {
    modint<mod> zeta = modint<mod>(primitive).pow((mod - 1) / (s << 1));
    for (i64 i = 0; i < n; i += (s << 1)) {
      modint<mod> zi = 1;
      for (i64 j = 0; j < s; j++) {
        modint<mod> t = a[i + j] - a[s + i + j];
        a[i + j] += a[s + i + j];
        a[s + i + j] = t * zi;
        zi = zi * zeta;
      }
    }
  }
  return a;
}

template <const i64 mod, const i64 primitive>
vector<modint<mod>> inverse_number_theoretic_transform(vector<modint<mod>> a) {
  i64 n = a.size();
  for (i64 s = 1; s < n; s <<= 1) {
    modint<mod> zeta =
        modint<mod>(primitive).pow((mod - 1) / (s << 1)).pow(mod - 2);
    for (i64 i = 0; i < n; i += (s << 1)) {
      modint<mod> zi = 1;
      for (i64 j = 0; j < s; j++) {
        modint<mod> t = a[s + i + j] * zi;
        a[s + i + j] = a[i + j] - t;
        a[i + j] = a[i + j] + t;
        zi = zi * zeta;
      }
    }
  }
  auto inv_n = modint<mod>(n).pow(mod - 2);
  for (int i = 0; i < n; i++)
    a[i] *= inv_n;
  return a;
}

template <const i64 mod, const i64 primitive> struct fps_ntt_multiply {
  using fps_type = modint<mod>;
  using conv_type = modint<mod>;
  static std::vector<conv_type> dft(std::vector<fps_type> arr) {
    return number_theoretic_transform<mod, primitive>(std::move(arr));
  }
  static std::vector<fps_type> idft(std::vector<conv_type> arr) {
    return inverse_number_theoretic_transform<mod, primitive>(std::move(arr));
  }
  static std::vector<conv_type> multiply(std::vector<conv_type> a,
                                         std::vector<conv_type> b) {
    for (int i = 0; i < a.size(); i++)
      a[i] *= b[i];
    return a;
  }
};

template <class T, class fps_multiply> struct FPS {
  std::vector<T> coef;

  static std::size_t bound_pow2(std::size_t sz) {
    return 1ll << (__lg(sz - 1) + 1);
  }

  FPS(const std::vector<T> &arr) : coef(arr) {}
  size_t size() const { return coef.size(); }
  void bound_resize() { this->coef.resize(bound_pow2(this->size())); }
  void resize_zero() {
    while (coef.size() > 1 && coef.back() == T(0)) {
      coef.pop_back();
    }
  }
  T operator[](int i) const {
    if (i < coef.size())
      return coef[i];
    else
      return T();
  }
  T &operator[](int i) { return coef[i]; }
  FPS pre(int n) const {
    std::vector<T> nex(n);
    for (int i = 0; i < coef.size() && i < n; i++)
      nex[i] = coef[i];
    return FPS(nex);
  }

  // F(0) must not be 0
  FPS inv() const {
    FPS g = FPS(std::vector<T>{T(1) / (*this)[0]});
    this->bound_resize();
    i64 n = this->size();
    for (int i = 1; i < n; i <<= 1) {
      g = g.pre(i << 1);
      auto gdft = fps_multiply::dft(g.coef);
      auto e = fps_multiply::idft(fps_multiply::multiply(
          fps_multiply::dft(this->pre(i << 1).coef), gdft));
      for (int j = 0; j < i; j++) {
        e[j] = T(0);
        e[j + i] = e[j + i] * T(-1);
      }
      auto f = fps_multiply::idft(
          fps_multiply::multiply(fps_multiply::dft(e), std::move(gdft)));
      for (int j = 0; j < i; j++) {
        f[j] = g[j];
      }
      g.coef = std::move(f);
    }
    return g.pre(n);
  }

  FPS diff() const {
    FPS res(vector<T>(this->size() - 1, T(0)));
    for (i64 i = 1; i < this->size(); i++)
      res[i - 1] = coef[i] * T(i);
    return res;
  }

  FPS integral() const {
    FPS res(vector<T>(this->size() + 1, T(0)));
    for (i64 i = 0; i < this->size(); i++)
      res[i + 1] = coef[i] / T(i + 1);
    return res;
  }

  // F(0) must be 0
  FPS log() const {
    return (this->diff() * this->inv()).integral().pre(this->size());
  }

  FPS exp() const {
    FPS f(vector<T>{T(1)});
    FPS g = *this;
    g.bound_resize();
    g[0] += T(1);
    for (i64 i = 1; i < size(); i <<= 1) {
      f = (f * (g.pre(i << 1) - f.pre(i << 1).log())).pre(i << 1);
    }
    return f;
  }

  FPS operator+(const FPS &rhs) {
    i64 n = std::max(this->size(), rhs.size());
    std::vector<T> ans(n);
    for (int i = 0; i < n; i++)
      ans[i] = (*this)[i] + rhs[i];
    return FPS(ans);
  }
  FPS operator-(const FPS &rhs) {
    i64 n = std::max(this->size(), rhs.size());
    std::vector<T> ans(n);
    for (int i = 0; i < n; i++)
      ans[i] = (*this)[i] - rhs[i];
    return FPS(ans);
  }
  FPS operator*(const FPS &rhs) {
    i64 m = this->size() + rhs.size() - 1;
    i64 n = bound_pow2(m);
    auto res = fps_multiply::idft(
        fps_multiply::multiply(fps_multiply::dft(this->pre(n).coef),
                               fps_multiply::dft(rhs.pre(n).coef)));
    res.resize(m);
    return res;
  }

  bool operator<(const FPS &rhs) const { return this->size() < rhs.size(); }
  bool operator>(const FPS &rhs) const { return this->size() > rhs.size(); }
};

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define rep(i, s, e) for (i64(i) = (s); (i) < (e); (i)++)
#define all(x) x.begin(), x.end()
#define STRINGIFY(n) #n
#define TOSTRING(n) STRINGIFY(n)
#define PREFIX "#" TOSTRING(__LINE__) "| "
#define debug(x)                                                               \
  { std::cout << PREFIX << #x << " = " << x << std::endl; }

std::ostream &output_indent(std::ostream &os, int ind) {
  for (int i = 0; i < ind; i++)
    os << " ";
  return os;
}

template <class S, class T>
std::ostream &operator<<(std::ostream &os, const std::pair<S, T> &p);
template <class T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v);

template <class S, class T>
std::ostream &operator<<(std::ostream &os, const std::pair<S, T> &p) {
  return (os << "(" << p.first << ", " << p.second << ")");
}
template <class T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v) {
  os << "[";
  for (int i = 0; i < v.size(); i++)
    os << v[i] << ", ";
  return (os << "]");
}

template <class T> static inline std::vector<T> ndvec(size_t &&n, T val) {
  return std::vector<T>(n, std::forward<T>(val));
}
template <class... Tail> static inline auto ndvec(size_t &&n, Tail &&...tail) {
  return std::vector<decltype(ndvec(std::forward<Tail>(tail)...))>(
      n, ndvec(std::forward<Tail>(tail)...));
}
template <class Cond> struct chain {
  Cond cond;
  chain(Cond cond) : cond(cond) {}
  template <class T> bool operator()(T &a, const T &b) const {
    if (cond(a, b)) {
      a = b;
      return true;
    }
    return false;
  }
};
template <class Cond> chain<Cond> make_chain(Cond cond) {
  return chain<Cond>(cond);
}

#include <tuple>
#include <vector>
using i64 = long long;

template <class T>
std::tuple<std::vector<T>, std::vector<T>, std::vector<T>>
build_factorial(int N) {
  std::vector<T> fact(N);
  std::vector<T> finv(N);
  std::vector<T> inv(N);
  fact[0] = T(1);
  for (int i = 1; i < N; i++) {
    fact[i] = fact[i - 1] * T(i);
  }
  finv[N - 1] = T(1) / fact[N - 1];
  for (int i = N - 1; i-- > 0;) {
    finv[i] = finv[i + 1] * T(i + 1);
  }
  for (int i = 0; i < N; i++) {
    inv[i] = fact[i - 1] * finv[i];
  }
  return std::make_tuple(std::move(fact), std::move(finv), std::move(inv));
}

using fp = modint<998244353>;
using fps = FPS<fp, fps_ntt_multiply<998244353, 3>>;

int main() {
  i64 N;
  cin >> N;
  vector<i64> cnt(101010);
  rep(i, 0, N * 2) {
    i64 a;
    cin >> a;
    cnt[a - 1]++;
  }

  auto [fact, finv, inv] = build_factorial<fp>(101010);
  fps meth(vector<fp>{fp(1)});

  vector<fp> setting;

  {
    fp now(1);
    setting.push_back(now);
    rep(i, 1, N + 1) {
      now *= fact[i * 2] * finv[i * 2 - 2] * finv[2];
      setting.push_back(now);
    }
  }

  priority_queue<fps, vector<fps>, greater<fps>> que;
  rep(x, 0, 101010) {
    if (cnt[x] <= 1)
      continue;
    vector<fp> vec;
    i64 c = cnt[x];
    for (i64 i = 0; i * 2 <= c; i++) {
      vec.push_back(fact[c] * finv[i * 2] * finv[c - i * 2] * setting[i] *
                    finv[i]);
    }
    que.push(fps(vec));
  }
  que.push(meth);
  while (que.size() > 1) {
    auto f = que.top();
    que.pop();
    auto g = que.top();
    que.pop();
    que.push(f * g);
  }
  meth = que.top();
  fp ans(0);
  rep(i, 0, meth.size()) {
    if (i > N)
      break;
    fp res = meth[i] * setting[N - i] * finv[N - i];
    if (i % 2 == 0) {
      ans += res;
    } else {
      ans -= res;
    }
  }
  cout << ans.value() << endl;
}