#include <bits/stdc++.h>
#include <atcoder/all>
#define MOD (int)(998244353)
using namespace std;
using namespace atcoder;

// as + bt = GCD(a,b) a,b:const s,t:var(any)
// return GCD(a,b)
long long extGCD(long long a, long long b, long long& s, long long& t) {
  s = 1, t = 0;
  long long u = 0, v = 1;
  while (b) {
    long long tmp = a / b;
    a -= b * tmp;
    s -= u * tmp;
    t -= v * tmp;
    swap(s, u);
    swap(t, v);
    swap(a, b);
  }
  return a;
}
// (mod)x+ay=1, calculate y -> a^-1 (mod m) (a,m : coprime)
long long calcinv(long long a, long long m) {
  long long s, t;
  extGCD(a, m, s, t);
  return (s + m) % m;
}

using P = pair<int, int>;
int n;
vector<vector<long long>> memo;
priority_queue<P, vector<P>, greater<P>> pq;

int main() {
  cin >> n;
  {
    map<int, int> mp;
    for (int i = 0; i < 2 * n; ++i) {
      int x;
      cin >> x;
      ++mp[x];
    }
    if (mp.size() == 1) {
      cout << 0 << endl;
      return 0;
    }
    for (auto [_, p] : mp) {
      vector<long long> v(1, 1);
      long long now = 1, cnt = 1;
      for (long long i = p; i > 1;) {
        (now *= i--) %= MOD;
        (now *= i--) %= MOD;
        (now *= calcinv(2 * cnt++, MOD)) %= MOD;
        v.push_back(now);
      }
      pq.push(P(v.size(), memo.size()));
      memo.push_back(v);
    }
  }
  while (pq.size() > 1) {
    P l = pq.top(), r;
    pq.pop();
    r = pq.top();
    pq.pop();
    memo[l.second] = convolution(memo[l.second], memo[r.second]);
    pq.push(P(memo[l.second].size(), l.second));
  }
  int id = pq.top().second;
  vector<long long> oddf(1, 1);
  for (int i = 3; i <= 2 * n; i += 2) {
    long long now = oddf.back() * i % MOD;
    oddf.push_back(now);
  }
  long long res = 0, len = memo[id].size();
  for (int i = 0; i < len; ++i) {
    long long now = memo[id][i] * oddf[n - i - 1] % MOD;
    if (i & 1)
      (res += MOD - now) %= MOD;
    else
      (res += now) %= MOD;
  }
  cout << res << endl;
  return 0;
}