Problem:
Score : 600 points

Problem Statement

There are 2N people numbered 1 through 2N.
The height of Person i is h_i.

How many ways are there to make N pairs of people such that the following conditions are satisfied?
Compute the answer modulo 998,244,353.

Each person is contained in exactly one pair.

For each pair, the heights of the two people in the pair are different.

Two ways are considered different if for some p and q, Person p and Person q are paired in one way and not in the other.

Constraints

1 \leq N \leq 50,000

1 \leq h_i \leq 100,000

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
h_1
:
h_{2N}

Output

Print the answer.

Sample Input 1

2
1
1
2
3

Sample Output 1

2

There are two ways:

Form the pair (Person 1, Person 3) and the pair (Person 2, Person 4).

Form the pair (Person 1, Person 4) and the pair (Person 2, Person 3).

Sample Input 2

5
30
10
20
40
20
10
10
30
50
60

Sample Output 2

516

Solution in C++ (Clang 10.0.0 with AC Library v1.1) (judge verdict: Runtime Error)

#include <atcoder/all>
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <functional>
#include <bitset>

using namespace std;
using namespace atcoder;
using lint = long long int;
long long int INF = 1001001001001001LL;
int inf = 1000000007;
long long int MOD = 1000000007LL;
double PI = 3.1415926535897932;

template<typename T1,typename T2>inline void chmin(T1 &a,const T2 &b){if(a>b) a=b;}
template<typename T1,typename T2>inline void chmax(T1 &a,const T2 &b){if(a<b) a=b;}

#define ALL(a) a.begin(),a.end()
#define RALL(a) a.rbegin(),a.rend()

/* do your best */
const long long MAXN = 1001024;

// a, b の最大公約数を返す O( log max(a, b) )
long long gcd(long long a, long long b) {
  if(b == 0) return a;
  return gcd(b, a % b);
}

// ax + by = 1 となるような (x, y) と gcd(a, b) を返す. gcd(a, b) = 1 の時、解が存在する.
long long extgcd(long long a, long long b, long long &x, long long &y){
  long long d = a;
  if(b != 0){
    d = extgcd(b, a, y, x);
    y -= (a / b) * x;
  }else{
    x = 1;
    y = 0;
  }
  return d;
}


// 区間 [a, b) に存在する素数の個数を返す関数

long long prime[MAXN];        // [a,b) の素数のうち i 番目の素数
bool is_prime[MAXN];    // 整数 i が素数であるかどうか
bool is_prime_ab[MAXN]; // 整数 i+a が素数であるかどうか

long long sieve(long long n) {
  long long res = 0; fill(is_prime, is_prime + MAXN, true);
  is_prime[0] = is_prime[1] = false; // 0 と 1 は素数ではない。
  for(long long i = 2; i <= n; ++i) {
    if(!is_prime[i]) continue;
    prime[res++] = i;
    for(long long j = 2 * i; j <= n; j += i) is_prime[j] = false; // 素数 i の倍数は素数ではない (ふるい(篩)にかける)
  }
  return res;
}

/*
long long segment_sieve(long long a, long long b){
  fill(is_prime, is_prime + MAXN, true);
  fill(is_prime_ab, is_prime_ab + MAXN, true);
  for(long long i = 2; i * i <= b - 1; i++) {
    if(!is_prime[i]) continue;
    for(long long j = 2 * i; j * j <= b - 1; j += i) is_prime[j] = false; // 素数 i で篩にかける
    for(long long j = a - a % i; j < b; j += i) {
      if(j < a) continue;
      if(is_prime_ab[j-a]) is_prime_ab[j-a] = false; // 素数 i で篩にかける
    }
  }

  long long res = 0;
  for(long long i = a; i < b; i++) if(is_prime_ab[i - a]) prime[res++] = i;
  return res;
}
*/

// ある整数の約数列挙
vector<long long> divisors(long long n) {
  vector<long long> res;
  for(long long i = 1; i*i <= n; ++i) {
    if(n % i != 0) continue;
    res.push_back(i);
    if(n/i == i) continue; // 上の行で追加済み。
    res.push_back(n/i);
  }
  sort(res.begin(), res.end());
  return res;
}


// 素因数分解
map<long long, long long> prime_factors(long long n) {
  map<long long, long long> res;
  if(n == 1) { // n=1 の素因数分解は n^1
    res[n] = 1;
    return res;
  }
  for(long long i = 2, _n = n; i*i <= _n; ++i) {
    while(n % i == 0) {
      ++res[i]; // 素数i^{res[i]}
      n /= i;
    }
  }
  if(n != 1) res[n] = 1;
  return res;
}


// 繰り返し 2 乗法
long long modpow(long long a, long long n) {
  long long res = 1;
  while (n > 0) {
    if (n & 1) res = res * a % MOD;
    a = a * a % MOD;
    n >>= 1;
  }
  return res;
}


// 逆元を求める. a と m は互いに素であることが要請される.
long long modinv(long long a, long long m) {
  long long b = m, u = 1, v = 0;
  while(b){
    long long t = a / b;
    a -= t * b; swap(a, b);
    u -= t * v; swap(u, v);
  }
  u %= m; 
  if (u < 0) u += m;
  return u;
}

long long fac[MAXN], finv[MAXN], inv[MAXN];

// 前処理 O(n)
void math_init(){
  fac[0] = fac[1] = 1;
  finv[0] = finv[1] = 1;
  inv[1] = 1;
  for(long long i = 2; i < MAXN; i++){
    fac[i] = fac[i - 1] * i % MOD;
    inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD;
    finv[i] = finv[i - 1] * inv[i] % MOD;
  }
}

// 二項係数計算 O(1)
long long COM(long long n, long long k){
  if (n < k) return 0;
  if (n < 0 || k < 0) return 0;
  return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}

// before your coding, you have to write a line "math_init()"

int main() {
  
  math_init();
  lint n; cin >> n;
  vector<lint> h(2 * n);
  vector<lint> cnt(100001, 0);
  for (int i = 0; i < n; i++) {
    cin >> h[i];
    cnt[h[i]]++;
  }

  vector<lint> inv2(2 * n, 1);
  inv2[0] = inv[2];
  for (int i = 1; i <= 100001; i++) {
    inv2[i] *= inv[2];
    inv2[i] %= MOD;
  }

  vector<lint> dp(1, 1);
  for (int i = 1; i < 100001; i++) {
    lint all = cnt[i];
    vector<lint> a(1, 1);
    lint r = 2;
    while (r <= all) {
      a.push_back(COM(all, r));
      r += 2;
    }

    dp = convolution(dp, a);
  }


  lint ans = 1;
  for (int i = 0; i < dp.size(); i++) {
    lint rest = 2 * n - i * 2;
    lint add = 1;
    add *= fac[rest];
    add %= MOD;
    add *= inv2[rest] % MOD;
    add %= MOD;
    // cerr << "add = " << add << endl;

    if (i % 2 == 0) {
      ans += add;
      ans %= MOD;
    } else {
      ans = ans - add + MOD;
      ans %= MOD;
    }
  }

  cout << ans << endl;
  return 0;
}