#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
typedef long double ld;

#ifdef LOCAL
#define Gene template< class
#define Rics printer& operator,
Gene c> struct rge{c b, e;};
Gene c> rge<c> range(c i, c j){ return {i, j};}
struct printer{
    ~printer(){cerr<<endl;}
    Gene c >Rics(c x){ cerr<<boolalpha<<x; return *this;}
    Rics(string x){cerr<<x;return *this;}
    Gene c, class d >Rics(pair<c, d> x){ return *this,"(",x.first,", ",x.second,")";}
    Gene ... d, Gene ...> class c >Rics(c<d...> x){ return *this, range(begin(x), end(x));}
    Gene c >Rics(rge<c> x){
        *this,"["; for(auto it = x.b; it != x.e; ++it)
            *this,(it==x.b?"":", "),*it; return *this,"]";}
};
#define debug() cerr<<"LINE "<<__LINE__<<" >> ", printer()
#define dbg(x) "[",#x,": ",(x),"] "
#define bits(x) bitset<22>(x)
#define tham getchar()
#endif

#define FASTIO ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define eq(x, y) (fabs((x)-(y))<error)
#define bt(i) (1LL<<(i))

mt19937_64 rng((unsigned)chrono::system_clock::now().time_since_epoch().count());
const ll mod = 998244353;
//const ld error = ;
const ld PI = acosl(-1);

//inline ll MOD(ll x, ll m = mod){
//    ll y = x % m;
//    return (y >= 0) ? y: y+m;
//}

//const int/ll inf = ;
const int nmax = 2e5+10;
///===========================================  template  =======================================================


ll modexpo(ll x, ll n, ll m){
    ll ret = 1;
    while(n){
        if(n&1) ret = ret * x % m;
        x = x * x % m;
        n >>= 1;
    }
    return ret;
}

typedef ll T;
typedef vector<T> poly;
poly roots;					//precomputed roots
ll M;						//mod to be remembered
int N;						//size of stored roots
//m = prime mod, rt = primitve root, max_n = maximum root precal
int precal(ll m, ll rt, int max_n = bt(22)){
    ll k = (m-1);
    N = 1, M = m;
    while(!(k&1) && N < max_n)  k>>=1, N<<=1;
    roots.resize(N+1);
    rt = modexpo(rt, k, M);
    roots[0] = 1;
    for(int i = 1; i<=N; i++)
        roots[i] = roots[i-1] * rt % M;
    return N;				//returns how many precalculated
}

#define nxt(i, m) ( (i)^m^(bt( 31-__builtin_clz((i)^m) )-1) )
//^this returns next to i after reversing w.r.t mask m

void NTT(poly &coefs, poly &values, bool invert = false)	//invert -> inverse DFT
{
    int n = (int)coefs.size(), lg_n = __builtin_ctz(n), mask = (int)bt(lg_n) - 1;
    values.resize(n);		//coefs MUST BE of size 2^k

    for(int i = 0, j = 0; j<n; j++, i = (int)nxt(i, mask))
        values[j] = coefs[i];			//filling values with ordered coefficients

    for(int len = 2, hlen = 1; len<=n; len<<=1, hlen<<=1)		//recursions from base level
        for(int i = 0; i<n; i+=len)			//each part in a level
            for(int j = 0, r = N/len; j < hlen; j++)	//the recursion
            {
                T w = (invert)? roots[N-j*r] : roots[j*r];
                T u = values[i+j], v = values[i+j+hlen]*w % M;
                values[i+j] = u + v;
                if(values[i+j] >= M) values[i+j] -= M;
                values[i+j+hlen] = u - v;
                if(values[i+j+hlen] < 0) values[i+j+hlen] += M;
            }

    if(invert){
        ll inv_n = modexpo(n, M-2, M);
        for(auto &x: values) x = x*inv_n % M;		//final division if inverting
    }
}

void multiply(poly &A, poly &B, poly &C)	//result is stored in C
{
    poly va, vb;
    int a = (int)A.size(), b = (int)B.size(), n = 1;
    while(n < a + b) n <<= 1;
    A.resize(n), B.resize(n);		//making polynomials large enough

    NTT(A, va), NTT(B, vb);			//NTT
    for(int i = 0; i<n; i++)  va[i] = va[i] * vb[i] % mod;	//mod if NTT
    NTT(va, C, true);				//NTT inverse

    C.resize(a+b-1);
}

vector<poly> P;


ll fac[nmax];
ll facinv[nmax];

void precalNCR(){
    fac[0] = 1;
    for(int i = 1; i<nmax; i++)
        fac[i] = fac[i-1] * i % mod;
    facinv[nmax-1] = modexpo(fac[nmax-1], mod-2, mod);
    for(int i = nmax-1; i>0; i--)
        facinv[i-1] = facinv[i] * i % mod;
}

ll ncr(int n, int r){
    if(r < 0 || n < r) return 0;
    return fac[n] * facinv[r] % mod * facinv[n-r] % mod;
}

int cnt[nmax];
ll oddfac[nmax];

int recurse(int l, int r){
    if(l == r) return l;

    int mid = (l+r)>>1;
    int lid = recurse(l, mid);
    int rid = recurse(mid+1, r);

    multiply(P[lid], P[rid], P[lid]);
    return lid;
}

int main(){
    FASTIO;

    precal(mod, 3, 1<<20);
    precalNCR();


    int n;
    cin>>n;
    for(int i = 0; i<2*n; i++){
        int x;
        cin>>x;
        cnt[x]++;
    }

    oddfac[0] = 1;
    for(int i = 2; i<=2*n; i+=2){
        oddfac[i] = oddfac[i-2] * (i-1) % mod;
    }

    for(int i = 1; i<nmax; i++){
        P.emplace_back(cnt[i]+1);
        P.back()[0] = 1;
        for(int j = 2; j<=cnt[i]; j+=2){
            P.back()[j] = ncr(cnt[i], j) * oddfac[j] % mod;
        }
    }


    int id = recurse(0, (int)P.size()-1);


    ll ans = 0;
    for(int i = 0; i<P[id].size(); i+=2){
        ll tmp = P[id][i] * oddfac[2*n-i];
//        debug(), dbg(tmp);
        if(i/2%2 == 0){
            ans += tmp;
        }
        else{
            ans -= tmp;
        }
        ans %= mod;
    }
    if(ans < 0)
        ans += mod;
    cout<<ans<<endl;

    return 0;
}


Measured memory_bytes: 53724