/*
                                                  
  _|_|                              _|  _|    _|  
_|    _|  _|  _|_|  _|_|_|_|        _|  _|  _|    
_|    _|  _|_|          _|          _|  _|_|      
_|    _|  _|          _|      _|    _|  _|  _|    
  _|_|    _|        _|_|_|_|    _|_|    _|    _|  
                                                                                                    
*/ 
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
//#define ls (rt<<1)
//#define rs (rt<<1|1)
#define vi vector<int>
#define pb push_back
#define mk make_pair
#define pii pair<int,int>
#define rep(i,a,b) for(int i=(a),i##end=(b);i<=i##end;i++)
#define fi first
#define se second
typedef long long ll;
using namespace std;
const int mod=998244353;
const int maxn=55000*2*2;
const int Maxn=2e6+100;
const int len_lim=55000*2;
int ksm(int num,int t){
	int res=1;
	for(;t;t>>=1,num=1ll*num*num%mod){
		if(t&1)res=1ll*res*num%mod;
	}
	return res;
}
struct NTT{
	int wn[2][Maxn],A[Maxn],B[Maxn],rev[Maxn];
	void get_wn(int len){
		for(int l=2;l<=(1<<len);l<<=1){
			int w1=ksm(3,(mod-1)/l),w0=ksm(3,mod-1-(mod-1)/l);
			wn[1][l>>1]=wn[0][l>>1]=1;
			for(int j=1;j<(l>>1);j++){
				wn[1][(l>>1)+j]=1ll*wn[1][(l>>1)+j-1]*w1%mod;
				wn[0][(l>>1)+j]=1ll*wn[0][(l>>1)+j-1]*w0%mod;
			}
		}
	}
	void get_rev(int len){rep(i,1,(1<<len)-1)rev[i]=(rev[i>>1]>>1)|((i&1)<<len-1);}
	void ntt(int len,int *c,int f){
		rep(i,0,len)if(rev[i]>i)swap(c[rev[i]],c[i]);//?
		for(int l=2;l<=len;l<<=1){
			for(int i=0;i+l<=len;i+=l){
				for(int j=i;j<i+(l>>1);j++){
					int tmp1=c[j]%mod,tmp2=1ll*wn[f][j-i+(l>>1)]*c[j+(l>>1)]%mod;
					c[j]=(tmp1+tmp2)%mod;
					c[j+(l>>1)]=(tmp1-tmp2+mod)%mod;
				}
			}
		}
		if(!f){
			int inv=ksm(len,mod-2);
			rep(i,0,len-1)c[i]=1ll*c[i]*inv%mod;
		}
	}
	vi mul(vi a,vi b){
		int l1=a.size(),l2=b.size();int len=1,cnt=0;while(len<=l1+l2)cnt++,len<<=1;
		get_rev(cnt);
		rep(i,0,len)A[i]=B[i]=0;
		rep(i,0,l1-1)A[i]=a[i];
		rep(i,0,l2-1)B[i]=b[i];
		ntt(len,A,1);ntt(len,B,1);
		rep(i,0,len-1)A[i]=1ll*A[i]*B[i]%mod;
		ntt(len,A,0);
		vi re;
		rep(i,0,len-1)re.pb(A[i]);
		re.resize(min(l1+l2,len_lim));
		return re;
	}
}t;
int h[maxn],bk[maxn],cnt[maxn];
int frac[maxn]; 
int C(int m,int n){
	return 1ll*frac[n]*ksm(1ll*frac[m]*frac[n-m]%mod,mod-2)%mod;
}
int g(int x){//x pair combine randomly
	return 1ll*frac[2*x]*ksm(1ll*frac[x]*ksm(2,x)%mod,mod-2)%mod;
}
vi gen[maxn];
vi solve(int l,int r){
	if(l==r)return gen[l];
	int mid=(l+r)>>1;
	vi debug=t.mul(solve(l,mid),solve(mid+1,r));
	return debug;
}
int tmp[maxn];
int main(){
	frac[0]=1;rep(i,1,maxn-1)frac[i]=1ll*i*frac[i-1]%mod;
	t.get_wn(20);
	ios::sync_with_stdio(0);
	int n;cin>>n;
	rep(i,1,2*n)cin>>h[i],bk[i]=h[i];
	sort(bk+1,bk+1+2*n);int mxid=unique(bk+1,bk+1+2*n)-bk-1;//??
	rep(i,1,2*n)h[i]=lower_bound(bk+1,bk+1+mxid,h[i])-bk,cnt[h[i]]++;
	rep(i,1,mxid){
		rep(j,0,cnt[i]/2){//use j pair
			gen[i].pb(1ll*C(2*j,cnt[i])*g(j)%mod);
		}
	}
	vi ans=solve(1,mxid);ans.resize(n+1);
	rep(i,0,n){
		tmp[i]=1ll*ans[i]*g(n-i)%mod;
	}
	int out=0;
	rep(i,0,n){
		out=(out+1ll*((i&1)?-1:1)*tmp[i])%mod;
	}
	out=(out+mod)%mod;
	cout<<out;
	return 0;
}


Measured memory_bytes: 24504