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 <algorithm>
#include <cassert>
#include <cctype>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <vector>
#include <list>
#define rep(i, n) for (int i = 0; i < (int)(n); ++i)
#ifdef DEBUG
#define show(...) cerr << #__VA_ARGS__ << " = ", debug(__VA_ARGS__);
#else
#define show(...) 42
#endif
using namespace std;
using ll = long long;
using pii = pair<int, int>;
template <typename T, typename S>
ostream& operator<<(ostream& os, pair<T, S> a) {
    os << '(' << a.first << ',' << a.second << ')';
    return os;
}
template <typename T>
ostream& operator<<(ostream& os, vector<T> v) {
    for (auto x : v) os << x << ' ';
    return os;
}
void debug() {
    cerr << '\n';
}
template <typename H, typename... T>
void debug(H a, T... b) {
    cerr << a;
    if (sizeof...(b)) cerr << ", ";
    debug(b...);
}

//負の数を掛けたりするとバグる
template<int MOD>
class Modint{
public:
    int a;
    Modint(const long long v = 0):a(v % MOD){}
    static constexpr int getmod(){
        return MOD;
    }
    Modint operator+(const Modint rhs) const{
        return Modint(*this) += rhs;
    }
    Modint operator-(const Modint rhs) const{
        return Modint(*this) -= rhs;
    }
    Modint operator*(const Modint rhs) const{
        return Modint(*this) *= rhs;
    }
    Modint operator/(const Modint rhs) const{
        return Modint(*this) /= rhs;
    }
    Modint operator+(const long long rhs) const{
        return Modint(*this) += rhs;
    }
    Modint operator-(const long long rhs) const{
        return Modint(*this) -= rhs;
    }
    Modint operator*(const long long rhs) const{
        return Modint(*this) *= rhs;
    }
    Modint operator/(const long long rhs) const{
        return Modint(*this) /= rhs;
    }
    friend Modint operator+(const long long a, const Modint b){
        return b + a;
    }
    friend Modint operator-(const long long a, const Modint b){
        return -b + a;
    }
    friend Modint operator*(const long long a, const Modint b){
        return b * a;
    }
    friend Modint operator/(const long long a, const Modint b){
        return Modint(a) / b;
    }
    Modint &operator+=(const Modint rhs){
        a += rhs.a;
        if(a >= MOD){
            a -= MOD;
        }
        return *this;
    }
    Modint &operator-=(const Modint rhs){
        if(a < rhs.a){
            a += MOD;
        }
        a -= rhs.a;
        return *this;
    }
    Modint &operator*=(const Modint rhs){
        a = (long long)a * rhs.a % MOD;
        return *this;
    }
    Modint &operator/=(Modint rhs){
        int x = MOD - 2;
        while(x){
            if(x % 2){
                *this *= rhs;
            }
            rhs *= rhs;
            x /= 2;
        }
        return *this;
    }
    Modint &operator++(){
        *this += 1;
        return *this;
    }
    Modint &operator--(){
        *this -= 1;
        return *this;
    }
    Modint operator++(int){
        Modint res = *this;
        ++(*this);
        return res;
    }
    Modint operator--(int){
        Modint res = *this;
        --(*this);
        return res;
    }
    Modint &operator+=(const long long rhs){
        *this += Modint(rhs);
        return *this;
    }
    Modint &operator-=(const long long rhs){
        *this -= Modint(rhs);
        return *this;
    }
    Modint &operator*=(const long long rhs){
        *this *= Modint(rhs);
        return *this;
    }
    Modint &operator/=(const long long rhs){
        *this /= Modint(rhs);
        return *this;
    }
    Modint operator+() const{
        return *this;
    }
    Modint operator-() const{
        return Modint()-*this;
    }
    bool operator==(const Modint rhs) const{
        return a == rhs.a;
    }
    bool operator==(const long long rhs) const{
        return a == rhs;
    }
    friend bool operator==(const long long a, const Modint b){
        return a == b.a;
    }
    bool operator!=(const Modint rhs) const{
        return a != rhs.a;
    }
    bool operator!=(const long long rhs) const{
        return a != rhs;
    }
    friend ostream &operator<<(ostream &os, const Modint x){
        os << x.a;
        return os;
    }
    friend istream &operator>>(istream &is, Modint &x){
        is >> x.a;
        return is;
    }
    explicit operator bool() const{
        return a > 0;
    }
    bool operator!(){
        return a == 0;
    }
    explicit operator int() const{
        return a;
    }
    explicit operator long long() const{
        return (long long) a;
    }
    friend Modint pow(Modint a, long long b){
        Modint res = 1;
        while(b){
            if(b % 2){
                res *= a;
            }
            a *= a;
            b /= 2;
        }
        return res;
    }
};
using mint = Modint<998244353>;
const int NUM = 400005;
mint fact[NUM + 1], fact_inv[NUM + 1], inv[NUM + 1];
mint combi(long long N_, long long K_){
    static const int Mod_ = fact[0].getmod();
    static_assert(NUM < Mod_, "");
    if(fact[0] == 0){
        inv[1] = fact[0] = fact_inv[0] = 1;
        for(int i = 2; i <= NUM; i++){
            inv[i] = inv[Mod_ % i] * (Mod_ - Mod_ / i);
        }
        for(int i = 1; i <= NUM; i++){
            fact[i] = fact[i - 1] * i;
            fact_inv[i] = fact_inv[i - 1] * inv[i];
        }
    }
    if(K_ < 0 or K_ > N_) return 0;
    return fact_inv[K_] * fact[N_] * fact_inv[N_ - K_];
}
mint hcomb(long long N_, long long K_){
    return ((N_ | K_) == 0) ? 1 : combi(N_ + K_ - 1, K_);
}
const mint g = 3;
void fft(vector<mint> &a, const bool rev = false){
    const int n = (int) a.size();
    assert((n & (n - 1)) == 0);
    if(n == 1)return;
    vector<mint> b, c;
    rep(i,n){
        (i & 1 ? c : b).push_back(a[i]);
    }
    fft(b, rev);
    fft(c, rev);
    mint w = 1;
    const mint t = pow(g, rev ? (mint::getmod()-1 -(mint::getmod()-1)/n) : (mint::getmod()-1)/n);
    rep(i,n){
        a[i] = b[i & ((n >> 1) - 1)] + w * c[i & ((n >> 1) - 1)];
        w *= t;
    }
}
vector<mint> mul(const vector<mint> &a, const vector<mint> &b){
    int s = (int) a.size() + (int) b.size() - 1;
    int t = 1;
    while(t < s) t *= 2;
    vector<mint> A(t), B(t);
    rep(i,a.size())A[i] = a[i];
    rep(i,b.size())B[i] = b[i];
    fft(A);
    fft(B);
    rep(i,t)A[i] *= B[i];
    fft(A, true);
    vector<mint> res(s);
    const mint inv = mint(1)/t;
    rep(i,s)res[i] = A[i] * inv;
    return res;
}
int cnt[200005];
mint inv2[200005];
int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
//    n = 50000;
    vector<int>h(2*n);
    rep(i,2*n){
        h[i] = rand()%(2*n);
        cin >> h[i];
        cnt[h[i]]++;
    }
    vector<int>a;
    rep(i,200005)if(cnt[i])a.push_back(cnt[i]);
    sort(a.begin(), a.end());
    vector<vector<mint>> dp;
    inv2[200004] = mint(1)/pow(mint(2),200004);
    for(int i = 200003; i >= 0; i--)inv2[i] = inv2[i+1] * 2;
    vector<int>q;
    for(int x: a){
        vector<mint>dp2;
        for(int i = 0; i <=x/2; i++){
            //iペア作る
            mint k =combi(x,2*i)*fact[2*i]*fact_inv[i]*inv2[i];
            dp2.push_back(k);
        }
        dp.push_back(dp2);
        q.push_back((int)dp.size()-1);
    }
    while(q.size()>1){
        vector<int>qq;
        rep(i,q.size()/2){
            dp[q[i*2]] = mul(dp[q[i*2]], dp[q[i*2+1]]);
            qq.push_back(q[i*2]);
        }
        if(q.size()&1)qq.push_back(q.back());
        q = qq;
    }
    mint ans = 0;
    auto dp2 = dp[q.front()];
    dp2.resize(n + 1);
    rep(i,n+1){
        mint k = fact[2*n-2*i]*fact_inv[n-i]*inv2[n-i] * dp2[i];
        if(i&1)ans -=k;
        else ans += k;
    }
    cout << ans << endl;
}