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++ (GCC 9.2.1) (judge verdict: Accepted)

#include <bits/stdc++.h>

//#include <atcoder/all>
#define For(i, a, b) for (int(i) = (int)(a); (i) < (int)(b); ++(i))
#define rFor(i, a, b) for (int(i) = (int)(a)-1; (i) >= (int)(b); --(i))
#define rep(i, n) For((i), 0, (n))
#define rrep(i, n) rFor((i), (n), 0)
#define fi first
#define se second
using namespace std;
typedef long long lint;
typedef unsigned long long ulint;
typedef pair<int, int> pii;
typedef pair<lint, lint> pll;
template <class T>
bool chmax(T &a, const T &b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
template <class T>
bool chmin(T &a, const T &b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template <class T>
T div_floor(T a, T b) {
    if (b < 0) a *= -1, b *= -1;
    return a >= 0 ? a / b : (a + 1) / b - 1;
}
template <class T>
T div_ceil(T a, T b) {
    if (b < 0) a *= -1, b *= -1;
    return a > 0 ? (a - 1) / b + 1 : a / b;
}

constexpr lint mod = 1000000007;
constexpr lint INF = mod * mod;
constexpr int MAX = 100010;

template <int_fast64_t MOD>
struct modint {
    using i64 = int_fast64_t;
    i64 a;
    modint(const i64 a_ = 0) : a(a_) {
        if (a > MOD)
            a %= MOD;
        else if (a < 0)
            (a %= MOD) += MOD;
    }
    modint inv() {
        i64 t = 1, n = MOD - 2, x = a;
        while (n) {
            if (n & 1) (t *= x) %= MOD;
            (x *= x) %= MOD;
            n >>= 1;
        }
        modint ret(t);
        return ret;
    }
    bool operator==(const modint x) const { return a == x.a; }
    bool operator!=(const modint x) const { return a != x.a; }
    modint operator+(const modint x) const { return modint(*this) += x; }
    modint operator-(const modint x) const { return modint(*this) -= x; }
    modint operator*(const modint x) const { return modint(*this) *= x; }
    modint operator/(const modint x) const { return modint(*this) /= x; }
    modint operator^(const lint x) const { return modint(*this) ^= x; }
    modint &operator+=(const modint &x) {
        a += x.a;
        if (a >= MOD) a -= MOD;
        return *this;
    }
    modint &operator-=(const modint &x) {
        a -= x.a;
        if (a < 0) a += MOD;
        return *this;
    }
    modint &operator*=(const modint &x) {
        (a *= x.a) %= MOD;
        return *this;
    }
    modint &operator/=(modint x) {
        (a *= x.inv().a) %= MOD;
        return *this;
    }
    modint &operator^=(lint n) {
        i64 ret = 1;
        while (n) {
            if (n & 1) (ret *= a) %= MOD;
            (a *= a) %= MOD;
            n >>= 1;
        }
        a = ret;
        return *this;
    }
    modint operator-() const { return modint(0) - *this; }
    modint &operator++() { return *this += 1; }
    modint &operator--() { return *this -= 1; }
    bool operator<(const modint x) const { return a < x.a; }
};

using mint = modint<998244353>;

vector<mint> fact;
vector<mint> revfact;

void setfact(int n) {
    fact.resize(n + 1);
    revfact.resize(n + 1);
    fact[0] = 1;
    rep(i, n) fact[i + 1] = fact[i] * mint(i + 1);

    revfact[n] = fact[n].inv();
    for (int i = n - 1; i >= 0; i--) revfact[i] = revfact[i + 1] * mint(i + 1);
}

mint getC(int n, int r) {
    if (n < r) return 0;
    return fact[n] * revfact[r] * revfact[n - r];
}

using poly = vector<mint>;

void ntt(poly &f, bool inverse) {
    int n = f.size();
    int bit_num = 0;
    while ((1 << bit_num) < n) ++bit_num;
    rep(i, n) {
        int j = 0;
        rep(k, bit_num) j |= (i >> k & 1) << (bit_num - k - 1);
        if (i < j) swap(f[i], f[j]);
    }

    for (int k = 1; k < n; k *= 2) {
        mint r_i = 1;
        mint r = mint(3) ^ (998244352 / (2 * k));
        if (inverse) r = r.inv();
        rep(i, k) {
            for (int j = 0; j < n; j += k * 2) {
                mint s = f[i + j];
                mint t = f[i + j + k] * r_i;
                f[i + j] = s + t;
                f[i + j + k] = s - t;
            }
            r_i *= r;
        }
    }

    if (inverse) {
        mint rsz = mint(n).inv();
        rep(i, n) f[i] *= rsz;
    }
}

poly conv(poly a, poly b) {
    int sz = a.size() + b.size() - 1;
    int n = 1;
    while (n < sz) n *= 2;
    a.resize(n);
    b.resize(n);

    ntt(a, false);
    ntt(b, false);

    rep(i, n) a[i] *= b[i];
    ntt(a, true);

    return a;
}

int main() {
    int n;
    scanf("%d", &n);
    setfact(2 * n);
    vector<int> cnt(MAX, 0);
    rep(i, 2 * n) {
        int h;
        scanf("%d", &h);
        ++cnt[h];
    }

    deque<poly> dq;
    rep(h, MAX) if (cnt[h]) {
        poly p(cnt[h] / 2 + 1);
        for (int i = 0; i * 2 <= cnt[h]; ++i) {
            p[i] =
                fact[cnt[h]] / ((mint(2) ^ i) * fact[i] * fact[cnt[h] - 2 * i]);
        }
        dq.push_back(p);
    }
    while (dq.size() >= 2) {
        dq.push_back(conv(dq[0], dq[1]));
        dq.pop_front();
        dq.pop_front();
    }

    mint ans = 0;
    rep(i, dq[0].size()) if (dq[0][i] != 0) {
        mint tmp = dq[0][i] * fact[2 * n - 2 * i] /
                   ((mint(2) ^ (n - i)) * fact[n - i]);
        if (i % 2 == 0)
            ans += tmp;
        else
            ans -= tmp;
    }
    printf("%lld\n", ans.a);
}