//region Template
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace std;
using namespace atcoder;
#ifdef LOCAL
#include <debug_prettyprint.hpp>
#else
#define debug(...) 42
#pragma GCC optimize("Ofast")
#pragma GCC target("avx")
#endif
#define FASTIO ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); cout<<fixed<<setprecision(12);
#define FOR(i, n) for(int i=0; i<int(n); i++)
#define RNG(i, f, t) for(int i=int(f); i<=int(t); i++)
#define REV(i, f, t) for(int i=int(f); i>=int(t); --i)
#define ALL(v) (v).begin(), (v).end()
#define EXIT(answer) { cerr<<"EXIT #"<<__LINE__<<endl; cout<<answer<<endl; exit(0); }
#define sz(v) int(v.size())
template<int,typename T> struct MINMAX{ T val; MINMAX(T val) : val(val) {} };
template<typename T> MINMAX<1,T> MAX(T val) { return MINMAX<1,T>(val); };
template<typename T> MINMAX<2,T> MIN(T val) { return MINMAX<2,T>(val); };
template<typename T, typename U> inline T& operator|=(T &lhs, MINMAX<1,U> rhs) { return lhs = max(lhs, rhs.val); }
template<typename T, typename U> inline T& operator|=(T &lhs, MINMAX<2,U> rhs) { return lhs = min(lhs, rhs.val); }
template<typename T, typename U> istream& operator>>(istream& in, pair<T,U> &p) { in>>p.first>>p.second; return in; }
template<typename T=int> inline vector<T> READ(int n) { vector<T> vec(n); FOR(i,n) cin>>vec[i]; return vec; }
template<typename T> using min_heap = priority_queue<T, vector<T>, greater<T> >;
typedef signed long long int ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vl;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
//endregion


//region ModInt
template <int m> struct ModInt {
//Source: https://github.com/atcoder/ac-library/blob/master/atcoder/modint.hpp (modified)
    unsigned int _v=0;
    static const unsigned int umod = m;
    ModInt(): _v(0) {}
    ModInt(long long v) {auto x = v % (long long)m; if (x<0) x += m; _v = x; }
    unsigned int val() const { return _v;  }
    ModInt& operator++() {_v++; if (_v==umod) _v = 0; return *this; }
    ModInt& operator--() {if (_v==0) _v = umod; _v--; return *this; }
    ModInt& operator+=(const ModInt& rhs) { _v += rhs._v; if (_v>=umod) _v -= umod; return *this; }
    ModInt& operator-=(const ModInt& rhs) { _v -= rhs._v; if (_v>=umod) _v += umod; return *this; }
    ModInt& operator*=(const ModInt& rhs) {unsigned long long z = _v; z *= rhs._v; _v = (unsigned int)(z % umod); return *this; }
    ModInt operator-() const { return ModInt() - *this; }
    ModInt pow(long long n) const {assert(0<=n); ModInt x = *this, r = 1; while (n) {if (n & 1) r *= x; x *= x; n >>= 1; } return r; }
    ModInt inv(){assert(m==1000000007 || m==998244353); return pow(umod - 2);}
    friend ModInt operator+(const ModInt& lhs, const ModInt& rhs) {return ModInt(lhs) += rhs; }
    friend ModInt operator-(const ModInt& lhs, const ModInt& rhs) {return ModInt(lhs) -= rhs; }
    friend ModInt operator*(const ModInt& lhs, const ModInt& rhs) {return ModInt(lhs) *= rhs; }
    friend bool operator==(const ModInt& lhs, const ModInt& rhs) {return lhs._v==rhs._v; }
    friend bool operator!=(const ModInt& lhs, const ModInt& rhs) {return lhs._v!=rhs._v; }
};
//endregion

//region Combinatorics
template<int N, typename mint> struct Combinatorics {
    mint _fac[N+1], _invfac[N+1];
    Combinatorics() {
        _fac[0] = _invfac[0] = 1;
        RNG(i,1,N) _invfac[i] = (_fac[i]=i*_fac[i-1]).inv();
    }
    mint fac(int n) {
        return _fac[n];
    }
    mint invfac(int n) {
        return _invfac[n];
    }
    mint binomial(int n, int k) {
        assert(k>=0 && k<=n);
        if(k==0 || n-k==0) return 1;
        return _fac[n] * _invfac[k] * _invfac[n - k];
    }
};
//endregion

const int MAXN = 1e5+5;
using mint = ModInt<998244353>;
using vm = vector<mint>;
Combinatorics<MAXN,mint> C;


mint pairs[MAXN];

signed main() {
    FASTIO

    pairs[0]=pairs[1]=1;
    RNG(i,2,MAXN-1)
        pairs[i] = i%2==0 ? pairs[i-1] : i*pairs[i-2];

    int n; cin>>n; n *= 2;
    vi h = READ(n);

    map<int,int> cnt;

    for(auto x : h)
        cnt[x]++;

    min_heap<pair<int,vi>> pq;

    for(auto e : cnt) {
        int ppl = e.second;
        vi poly = {1};
        for(int i=1; i<=ppl/2; i++) {
            mint ways = C.binomial(ppl, i*2) * pairs[i*2];
            poly.push_back(ways.val());
        }
        pq.push({poly.size(), poly});
    }

    while(pq.size()>=2) {
        vi a = pq.top().second; pq.pop();
        vi b = pq.top().second; pq.pop();
        vi c = convolution<998244353>(a,b);
        pq.push({c.size(),c});
    }

    vi poly = pq.top().second;

    mint ans=0;

    FOR(i,poly.size()) {
        int sgn = i%2 ? -1 : 1;
        ans += sgn * poly[i] * pairs[n-i*2];
    }

    cout<<ans.val()<<endl;
}

Measured memory_bytes: 15796