#include using namespace std; #define rep(i, x, limit) for (long long i = (long long)x; i < (long long)limit; i++) #define REP(i, x, limit) for (long long i = (long long)x; i <= (long long)limit; i++) #define all(x) x.begin(), x.end() #define rall(x) x.rbegin(), x.rend() #define el '\n' #define spa " " #define Yes cout << "Yes" << el #define No cout << "No" << el #define YES cout << "YES" << el #define NO cout << "NO" << el #define eps (1e-10) #define Equals(a,b) (fabs((a) - (b)) < eps ) #define debug(x) cerr << #x << " = " << x << el using ll = long long; using ull = unsigned long long; using pii = pair; using pll = pair; using vi = vector; using vl = vector; using vvl = vector>; using vs = vector; using vb = vector; const double pi = 3.141592653589793238; const int inf = 1073741823; const ll infl = 1LL << 60; const string ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const string abc = "abcdefghijklmnopqrstuvwxyz"; const ll MOD = 998244353; #include using namespace atcoder; using mint = modint998244353; using vm = vector; vector fact, invf; // a^e mod を繰り返し二乗法で計算 long long modpow(long long a, long long e) { long long r = 1; while (e > 0) { if (e & 1) r = r * a % MOD; a = a * a % MOD; e >>= 1; } return r; } // 0! から N! までの fact, invf を前計算 void init_factorials(int N) { fact.assign(N+1, 1); rep(i,0, N) fact[i+1] = fact[i] * (i+1) % MOD; invf.assign(N+1, 1); // invf[N] = (N!)^{-1} mod invf[N] = modpow(fact[N], MOD-2); for (int i = N; i > 0; --i) { invf[i-1] = invf[i] * i % MOD; } } // nCk mod を O(1) で返す long long comb(int n, int k) { if (k < 0 || k > n) return 0; return fact[n] * (invf[k] * invf[n-k] % MOD) % MOD; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); ll k;cin>>k; ll t=0; vector S; rep(i,0,k){ ll l,m;cin>>l>>m; t+=l*m; S.push_back({l,m}); } init_factorials(t); mint ans=1; for(auto [l,m]:S){ ll nt=l*m; ans*=comb(t,nt); t-=l*m; rep(i,0,m){ ans*=comb(nt-1,l-1); nt-=l; } } cout<