#include<cstdio> #include<iostream> #include<vector> #include<queue> using namespace std; typedef long long ll; const int maxn=3e5+10, mod = 998244353, G = 3, Gi = 332748118; typedef pair<int, int> P; ll quick(ll a,ll b,ll m) { ll ans=1; while(b>0) { if(b&1) ans=ans*a%m; a=a*a%m; b>>=1; } return ans; } ll jiecheng[maxn]; void ini_zuhelogn() { jiecheng[0]=1; for(int i=1;i<maxn;i++) { jiecheng[i]=jiecheng[i-1]*i%mod; } } ll zuhe_logn(int m,int n) { if(jiecheng[0]!=1) ini_zuhelogn(); ll ans=((jiecheng[m]*quick(jiecheng[n], mod-2, mod))%mod)*quick(jiecheng[m-n], mod-2, mod)%mod; return ans; } ll result_len,result[maxn],level=0,trans[maxn]; inline void NTT(ll *A, int type) { for(int i = 0; i < result_len; i++) if(i < trans[i]) swap(A[i], A[trans[i]]); for(int mid = 1; mid < result_len; mid <<= 1) { ll Wn = quick( type == 1 ? G : Gi , (mod - 1) / (mid << 1),mod); for(int j = 0; j < result_len; j += (mid << 1)) { ll w = 1; for(int k = 0; k < mid; k++, w = (w * Wn) % mod) { int x = A[j + k], y = w * A[j + k + mid] % mod; A[j + k] = (x + y) % mod, A[j + k + mid] = (x - y + mod) % mod; } } } } void ntt(ll *a,int a_len,ll *b,int b_len) { result_len=1;level=0; while(result_len<=a_len+b_len) { result_len<<=1; level++; } for(int i=a_len;i<result_len;i++) a[i]=0; for(int i=b_len;i<result_len;i++) b[i]=0; for(int i=0;i<result_len;i++) trans[i]=(trans[i>>1]>>1)|((i&1)<<(level-1)); NTT(a, 1); NTT(b, 1); for(int i=0;i<result_len;i++) result[i]=(a[i]*b[i])%mod; NTT(result,-1); ll inv=quick(result_len, mod-2, mod); for(int i=0;i<result_len;i++) result[i]=(result[i]*inv)%mod; } P a[maxn]; vector<ll> D[maxn]; priority_queue<P> q; ll d1[maxn],d2[maxn]; int main() { ini_zuhelogn(); int T; cin>>T; while (T--) { int n,m=0; cin>>n; for(int i=0;i<n;i++) { // cout<<i<<":"<<endl; cin>>a[i].first>>a[i].second; m+=a[i].first; int t=min(a[i].first,a[i].second); D[i].clear(); D[i].push_back(1); for(int j=1;j<=t;j++){ D[i].push_back((zuhe_logn(a[i].first, j)*zuhe_logn(a[i].second, j))%mod*jiecheng[j]%mod); // cout<<D[i][j]<<" "; } // cout<<endl; q.push(make_pair(-t-1, i)); } while(q.size()>1) { int t1=q.top().second,len1=-q.top().first; q.pop(); int t2=q.top().second,len2=-q.top().first; q.pop(); // cout<<t1<<" "<<len1<<": "; for(int i=0;i<len1;i++){ d1[i]=D[t1][i]; // cout<<d1[i]<<" "; } // cout<<endl<<t2<<" "<<len2<<": "; for(int i=0;i<len2;i++){ d2[i]=D[t2][i]; // cout<<d2[i]<<" "; } // cout<<endl; ntt(d1, len1, d2, len2); D[t2].clear(); for(int i=0;i<len1-1+len2;i++){ // cout<<result[i]<<" "; D[t2].push_back(result[i]); } // cout<<endl; q.push(make_pair(-len1+1-len2, t2)); } int t=q.top().second,len=-q.top().first; q.pop(); int flag=1; ll ans=0; for(int i=0;i<len;i++) { ans=(ans+flag*jiecheng[m-i]*D[t][i])%mod; flag*=-1; } cout<<(ans+mod)%mod<<endl; } return 0; } //1 //6 //0 2 //1 0 //1 2 //0 0 //2 2 //2 0