#include <bits/stdc++.h>
#include <atcoder/all>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
using namespace atcoder;
#ifdef ENABLE_DEBUG
#define dump(a) cerr<<#a<<"="<<a<<endl
#define dumparr(a,n) cerr<<#a<<"["<<n<<"]="<<a[n]<<endl
#else
#define dump(a) 
#define dumparr(a,n) 
#endif
#define FOR(i, a, b) for(ll i = (ll)a;i < (ll)b;i++)
#define For(i, a) FOR(i, 0, a)
#define REV(i, a, b) for(ll i = (ll)b-1LL;i >= (ll)a;i--)
#define Rev(i, a) REV(i, 0, a)
#define REP(a) For(i, a)
#define SIGN(a) (a==0?0:(a>0?1:-1))

typedef long long int ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef pair<ll, ll> pll;
typedef pair<ll,pll> ppll;
typedef vector<ll> vll;
typedef long double ld;
typedef pair<ld,ld> pdd;

pll operator+(pll a,pll b){
  return pll(a.first+b.first,a.second+b.second);
}
pll operator-(pll a,pll b){
  return pll(a.first-b.first,a.second-b.second);
}
pll operator*(ll a,pll b){
  return pll(b.first*a,b.second*a);
}
const ll INF=(1LL<<60);
#if __cplusplus<201700L
ll gcd(ll a, ll b) {
  a=abs(a);
  b=abs(b);
  if(a==0)return b;
  if(b==0)return a;
  if(a < b) return gcd(b, a);
  ll r;
  while ((r=a%b)) {
    a = b;
    b = r;
  }
  return b;
}
#endif
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 S,class T>
std::ostream& operator<<(std::ostream& os,pair<S,T> a){
  os << "(" << a.first << "," << a.second << ")";
  return os;
}
template<class T>
std::ostream& operator<<(std::ostream& os,deque<T> a){
  os << "[ ";
  REP(a.size()){
    os<< a[i] << " ";
  }
  os<< " ]";
  return os;
}
template<class T>
std::ostream& operator<<(std::ostream& os,vector<T> a){
  os << "[ ";
  REP(a.size()){
    os<< a[i] << " ";
  }
  os<< " ]";
  return os;
}

const long long MOD = 998244353;
const long long max_cache=1000000;
long long cache_ffact[max_cache],cache_fact[max_cache],cache_inv_fact[max_cache];
long long combination_cached(long long n,long long r){
  const ll m=MOD;
  static bool cached=false;
  if(cached==false){
    cached=true;
    cache_inv_fact[1]=1;
    for (long long i = 2; i < max_cache; i++) {
      cache_inv_fact[i]=(m-m/i)*cache_inv_fact[m%i]%m;
    }
    for (long long i = 2; i < max_cache; i++){
      cache_inv_fact[i]=cache_inv_fact[i]*cache_inv_fact[i-1]%m;
    }
    cache_fact[0]=1;
    for (long long i = 1; i < max_cache; i++) {
      cache_fact[i]=cache_fact[i-1]*i%m;
    }
    cache_ffact[0]=1;
    for (ll i=1;i < max_cache; i++){
      cache_ffact[i]=cache_ffact[i-1]*(2*i-1)%m;
    }
  }
  if(r<0||r>n)return 0;
  if(r==0||r==n)return 1;
  if(n>m){
    std::cerr<<"Combination Error: n is greater than m"<<std::endl;
    abort();
  }
  r=min(r,n-r);
  return cache_fact[n]*cache_inv_fact[r]%m*cache_inv_fact[n-r]%m;
}
ll F[100010],inv[100010],Finv[100010];
ll G[100010];
void solve(long long N, std::vector<long long> h){
  combination_cached(1,1);
  vector<ll> mp(100010);
  REP(h.size()){
    mp[h[i]]++;
  }
  vector<ll> st;
  REP(mp.size()){
    if(mp[i]>0){
      st.push_back(mp[i]);
    }
  }
  deque<vector<ll>> dp;
  for (auto &&i : st)
  {
    vector<ll> tmp{1};
    FOR(j,1,i/2+1){
      tmp.push_back(combination_cached(i,2*j)*cache_ffact[j]%MOD);
    }
    dp.push_back(move(tmp));
  }
  auto PP=dp;
  while(dp.size()>1){
    dp.push_back(convolution(move(dp[0]),move(dp[1])));
    dp.pop_front();dp.pop_front();
  }
  {
    ll ans=0;
    REP(dp.size()){
      if(i%2==0){
        ans=(ans+dp[0][i]*cache_ffact[(N-i)]%MOD)%MOD;
      }else{
        ans=(ans+(MOD-dp[0][i]*cache_ffact[(N-i)]%MOD))%MOD;
      }
    }

  }
  {
    int i, j;

    inv[1] = 1;
    for (i = 2; i < 100010; i++)
      inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;

    F[0] = Finv[0] = 1;
    for (i = 1; i < 100010; i++)
    {
      F[i] = F[i - 1] * i % MOD;
      assert(F[i]==cache_fact[i]);
      Finv[i] = Finv[i - 1] * inv[i] % MOD;
      assert(Finv[i]==cache_inv_fact[i]);
    }

    G[0] = 1;
    for (i = 1; i < 100010; i++){
      G[i] = G[i - 1] * (2 * i - 1) % MOD;
      assert(G[i]==cache_ffact[i]);
    }

    deque<vector<ll>> P;

    For(i, 100010)if (mp[i] > 0)
    {
      int n = mp[i];
      vector<ll> v(n / 2 + 1);
      For(j, n / 2 + 1)
      {
        ll tmp = F[n] * Finv[2 * j] % MOD * Finv[n - 2 * j] % MOD * G[j] % MOD;
        assert(tmp==PP[P.size()][j]);
        if (j % 2 == 1)
          tmp = (MOD - tmp) % MOD;
        v[j] = tmp;
      }
      P.push_back(v);
    }
    while (P.size() > 1)
    {
      vector<ll> v = convolution(P[0], P[1]);
      P.pop_front();
      P.pop_front();
      P.push_back(v);
    }

    ll ans = 0;
    For(i, P[0].size()){
      ans = (ans + (i%2?(MOD-dp[0][i]):dp[0][i]) * G[N - i]) % MOD;
      if(i%2==0)assert(P[0][i]==dp[0][i]);
      else assert(P[0][i]==(MOD-dp[0][i]));
    }
    cout<<ans<<endl;
  }
}

int main(){
  cout<<setprecision(1000);
    long long N;
    scanf("%lld",&N);
    std::vector<long long> h(2*N);
    for(int i = 0 ; i < 2*N ; i++){
        scanf("%lld",&h[i]);
        --h[i];
    }
    solve(N, std::move(h));
    return 0;
}


Measured memory_bytes: 43160