//雪花飄飄北風嘯嘯
//天地一片蒼茫

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>
using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;
#define ll long long
#define ii pair<ll,ll>
#define iii pair<ii,ll>
#define fi first
#define se second
#define endl '\n'
#define debug(x) cout << #x << " is " << x << endl

#define rep(x,start,end) for(auto x=(start)-((start)>(end));x!=(end)-((start)>(end));((start)<(end)?x++:x--))
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()

#define indexed_set tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>
//change less to less_equal for non distinct pbds, but erase will bug

mt19937 rng(chrono::system_clock::now().time_since_epoch().count());

const int MOD=998244353,mod=(119<<23)+1,root=62;

ll qexp(ll b,ll p,int m=998244353){
    ll res=1;
    while (p){
        if (p&1) res=(res*b)%m;
        b=(b*b)%m;
        p>>=1;
    }
    return res;
}

ll inv(int i){
	return qexp(i,MOD-2,MOD);
}

typedef vector<ll> vl;
typedef vector<int> vi;
void ntt(vl &a) {
	int n = sz(a), L = 31 - __builtin_clz(n);
	static vl rt(2, 1);
	for (static int k = 2, s = 2; k < n; k *= 2, s++) {
		rt.resize(n);
		ll z[] = {1, qexp(root, mod >> s)};
		rep(i,k,2*k) rt[i] = rt[i / 2] * z[i & 1] % mod;
	}
	vi rev(n);
	rep(i,0,n) rev[i] = (rev[i / 2] | (i & 1) << L) / 2;
	rep(i,0,n) if (i < rev[i]) swap(a[i], a[rev[i]]);
	for (int k = 1; k < n; k *= 2)
		for (int i = 0; i < n; i += 2 * k) rep(j,0,k) {
			ll z = rt[j + k] * a[i + j + k] % mod, &ai = a[i + j];
			a[i + j + k] = ai - z + (z > ai ? mod : 0);
			ai += (ai + z >= mod ? z - mod : z);
		}
}
vl conv(const vl &a, const vl &b) {
	if (a.empty() || b.empty()) return {};
	int s = sz(a) + sz(b) - 1, B = 32 - __builtin_clz(s), n = 1 << B;
	int inv = qexp(n, mod - 2);
	vl L(a), R(b), out(n);
	L.resize(n), R.resize(n);
	ntt(L), ntt(R);
	rep(i,0,n) out[-i & (n - 1)] = (ll)L[i] * R[i] % mod * inv % mod;
	ntt(out);
	return {out.begin(), out.begin() + s};
}

ll fac[100005];

ll ways(int i,int j){ 
	return fac[i]*inv(qexp(2,j,MOD))%MOD*inv(fac[i-2*j])%MOD*inv(fac[j])%MOD;
}

int n;
int arr[100005];
int cnt[100005];
vector<ll> v[100005];
priority_queue<ii,vector<ii>,greater<ii> > pq;

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin.exceptions(ios::badbit | ios::failbit);
	
	fac[0]=1;
	rep(x,1,100005) fac[x]=(fac[x-1]*x)%MOD;
	
	cin>>n;
	rep(x,0,2*n) cin>>arr[x];
	rep(x,0,2*n) cnt[arr[x]]++;
	
	v[0]={1};
	pq.push(ii(1,0));
	
	rep(x,1,100001) if (cnt[x]>=2){
		rep(y,0,cnt[x]/2+1){
			v[x].push_back(ways(cnt[x],y));
		}
		pq.push(ii(sz(v[x]),x));
		//cout<<x<<":"<<endl;
		//for (auto &it:v[x]) cout<<it<<" "; cout<<endl;
	}
	
	int a,b;
	while (sz(pq)>1){
		a=pq.top().se,pq.pop();
		b=pq.top().se,pq.pop();
		
		v[a]=conv(v[a],v[b]);
		pq.push(ii(sz(v[a]),a));
	}
	
	a=pq.top().se;
	
	//for (auto &it:v[a]) cout<<it<<" "; cout<<endl;
	
	ll ans=0;
	rep(x,0,sz(v[a])){
		ll temp=ways(2*(n-x),(n-x));
		
		if (x&1) ans=(ans-v[a][x]*temp)%MOD;
		else ans=(ans+v[a][x]*temp)%MOD;
	}
	
	cout<<(ans+MOD)%MOD<<endl;
	
	//cout<<ways(10,5)-ways(8,4)*5+ways(6,3)*7-ways(4,2)*3<<endl;
	
	//cout<<ways(6,0)<<endl;
	//cout<<ways(4,2)<<endl;
	
}





Measured memory_bytes: 14988