#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>

// using namespace __gnu_pbds;
using namespace std;

#define fbo find_by_order
#define ook order_of_key
#define fi first
#define se second
#define long long long
#define mul(a, b) (1LL*a*b)%MOD
#define add(a, b) (a+b)%MOD
#define dec(a, b) (a-b+MOD)%MOD
typedef pair<int,int> ii;
typedef pair<int,ii> iii;
typedef vector<int> vi;
typedef vector<ii> vii;
// typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;
// mt19937_64 rng(std::chrono::system_clock::now().time_since_epoch().count());

// /mnt/c/Users/vince/Desktop/POST-IOI/  

const long MOD = 998244353;
long fac[100003], ifac[100003];
long D[100003];

long pwr(long a, long b)
{
	if(b == 0) return 1;
	else if(b == 2) return mul(a,a);
	else if(b&1) return (pwr(a,b-1)*a)%MOD;
	else return pwr(pwr(a,b/2),2);
}

long C(long a, long b)
{
	if(b > a) return 0;
	return ((fac[a]*ifac[a-b])%MOD*ifac[b])%MOD;
}


vector<long> FFT(vector<long> A)
{
	int n = A.size();
	if(n == 1) return A;

	long Wn = pwr(2,119*pwr(2,23-int(log2(n)+1)));
	long W = 1;

	vector<long> Ae, Ao;
	vector<long> Ye, Yo, Y;
	Y.assign(n, 0);
	for(int i = 0; i < n; i+=2) Ae.push_back(A[i]); 
	for(int i = 1; i < n; i+=2) Ao.push_back(A[i]);
	Ye = FFT(Ae);
	Yo = FFT(Ao);
	for(int i = 0 ; i <= n/2-1; i++)
	{
		Y[i] = (Ye[i] + (W * Yo[i])%MOD)%MOD;
		Y[i+n/2] = dec(Ye[i],mul(W, Yo[i]));
		W = (W*Wn)%MOD;
	}
	return Y;
}

vector<long> IFFT(vector<long> Y)
{
	Y = FFT(Y);
	for(int i = 0; i < Y.size(); i++)
	{
		Y[i] *= pwr(Y.size(), MOD-2);
		Y[i] %= MOD;
	}
	reverse(Y.begin()+1, Y.end());
	return Y;
}

// multiplicaton of 2 polinomial in O(n log n) with FFT
// 
vector<long> operator* (vector<long> A, vector<long> B)
{
	int sz = A.size() + B.size();
	int x = 1;
	while(x < sz) x *= 2;
	while(A.size() < x) A.push_back(0);
	while(B.size() < x) B.push_back(0);

	vector<long> YA = FFT(A);
	vector<long> YB = FFT(B);
	vector<long> YC(YA.size());
	for(int i = 0; i < YA.size(); i++) { YC[i] = (YA[i]*YB[i])%MOD; }
	
	YC = IFFT(YC);
	while(YC.back() == 0) YC.pop_back();
	return YC;
}

struct dat
{
	vector<long> vec;
	bool operator< (const dat &rhs) const {
		if(vec.size() != rhs.vec.size()) return vec.size() < rhs.vec.size();
		else return vec < rhs.vec;
	}

	dat(vector<long> vec) {this->vec = vec;}
};
int n;
int cnt[100003];

int main()
{
	// ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	// freopen("input.in", "r", stdin);

	fac[0] = ifac[0] = 1;
	D[0] = D[2] = 1;
	for(int i = 4; i <= 100000; i++) D[i] = mul(D[i-2],(i-1));
	for(int i = 1; i <= 100000; i++)
	{
		fac[i] = (fac[i-1]*i)%MOD;
		ifac[i] = pwr(fac[i], MOD-2);
	}
	
	scanf("%d", &n);
	n += n;
	for(int i = 1; i <= n; i++)
	{
		int x; scanf("%d", &x);
		cnt[x]++;
	}

	multiset<dat> st  = {dat({1})};
	for(int i = 1; i <= 100000; i++)
	{
		if(cnt[i] < 2) continue;
		vector<long> vec;
		for(int j = 0; 2*j <= cnt[i]; j++)
			vec.push_back((C(cnt[i], 2*j)*D[2*j])%MOD);

		st.insert(dat(vec));
	}
	while(st.size() >= 2)
	{
		vector<long> A = st.begin()->vec; st.erase(st.begin());
		vector<long> B = st.begin()->vec; st.erase(st.begin());
		st.insert(dat(A*B));
	}

	vector<long> dp = st.begin()->vec;
	long res = 0;
	int tanda = 1;
	for(int i = 0; i < dp.size(); i++)
	{
		// printf("%d %lld %lld\n", i, dp[i], D[n-2*i]);
		res = add(res,mul(tanda,mul(dp[i],D[n-2*i])));
		tanda *= -1;
	}
	printf("%lld\n", (res+MOD)%MOD);
}






Measured memory_bytes: 14592