#include <bits/stdc++.h>
using namespace std;
const uint64_t seed = std::chrono::system_clock::now().time_since_epoch().count();
mt19937_64 rnd(seed);
const int MOD = 998244353;

#ifdef VIPJML_LOCAL
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v)
{
    os << "{";
    for (typename vector<T>::const_iterator vi = v.begin(); vi != v.end(); ++vi)
    {
        if (vi != v.begin())
            os << ", ";
        os << *vi;
    }
    os << "}";
    return os;
}
template <typename A, typename B>
ostream &operator<<(ostream &os, const vector<pair<A, B>> &v)
{
    os << "{";
    for (typename vector<pair<A, B>>::const_iterator vi = v.begin(); vi != v.end(); ++vi)
    {
        if (vi != v.begin())
            os << ", ";
        os << '(' << vi->first << " " << vi->second << ")";
    }
    os << "}";
    return os;
}

template <typename A, typename B>
ostream &operator<<(ostream &os, const pair<A, B> &p)
{
    os << '(' << p.first << ", " << p.second << ')';
    return os;
}

void dbg_out() { cerr << endl; }
template <typename Head, typename... Tail>
void dbg_out(Head H, Tail... T)
{
    cerr << ' ' << H;
    dbg_out(T...);
}
#define dbg(...) cerr << "(" << #__VA_ARGS__ << "):", dbg_out(__VA_ARGS__)
#else
#define dbg(...)
#endif
using LL = long long;

struct Mint
{
    int v;
    Mint() : v(0) {}
    Mint(int t)
    {
        v = t % MOD;
        if (v < 0)
            v += MOD;
    }

    Mint pow(long long k)
    {
        Mint res(1), tmp(v);
        while (k)
        {
            if (k & 1)
                res *= tmp;
            tmp *= tmp;
            k >>= 1;
        }
        return res;
    }

    Mint inv() { return pow(MOD - 2); }

    Mint &operator+=(Mint a)
    {
        v += a.v;
        if (v >= MOD)
            v -= MOD;
        return *this;
    }
    Mint &operator-=(Mint a)
    {
        v += MOD - a.v;
        if (v >= MOD)
            v -= MOD;
        return *this;
    }

    static unsigned fast_mod(uint64_t x, unsigned m = MOD) {
#if !defined(_WIN32) || defined(_WIN64)
    return unsigned(x % m);
#endif
    // Optimized mod for Codeforces 32-bit machines.
    // x must be less than 2^32 * m for this to work, so that x / m fits in an unsigned 32-bit int.
    unsigned x_high = unsigned(x >> 32), x_low = unsigned(x);
    unsigned quot, rem;
    asm("divl %4\n"
      : "=a" (quot), "=d" (rem)
      : "d" (x_high), "a" (x_low), "r" (m));
    return rem;
  }

    Mint &operator*=(Mint a)
    {
        v = fast_mod(uint64_t(v) * a.v);
        return *this;
    }
    Mint &operator/=(Mint a) { return (*this) *= a.inv(); }

    Mint operator+(Mint a) const { return Mint(v) += a; }
    Mint operator-(Mint a) const { return Mint(v) -= a; }
    Mint operator*(Mint a) const { return Mint(v) *= a; }
    Mint operator/(Mint a) const { return Mint(v) /= a; }

    Mint operator-() const { return v ? Mint(MOD - v) : Mint(v); }

    bool operator==(const Mint a) const { return v == a.v; }
    bool operator!=(const Mint a) const { return v != a.v; }
    bool operator<(const Mint a) const { return v < a.v; }

    static Mint comb(long long n, int k)
    {
        Mint num(1), dom(1);
        for (int i = 0; i < k; i++)
        {
            num *= Mint(n - i);
            dom *= Mint(i + 1);
        }
        return num / dom;
    }

    static Mint inv(int n)
    {
        return Mint(n).inv();
    }

    static vector<Mint> getInvArray(int N)
    {
        vector<Mint> inv(N + 1, 1);
        for (int i = 2; i <= N; i++)
            inv[i] = inv[MOD % i] * (MOD - MOD / i);
        return inv;
    }
};

ostream &operator<<(ostream &os, Mint m)
{
    os << m.v;
    return os;
}

namespace NTT
{
    const int G = 3;
    const int LOGN = 15;
    vector<Mint> w[LOGN];
    vector<int> rv[LOGN];

    void prepare()
    {
         for(int st=0;st<LOGN;st++)
        {
            w[st].assign(1 << st, 1);
            Mint bw = Mint(G).pow((MOD-1)/(1 << st));
            Mint cw = 1;
            for(int k=0;k<( 1 << st);k++) {
                w[st][k] = cw;
                cw *= bw;
            } 
        }
        for(int st=0;st<LOGN;st++)
        {
            rv[st].assign(1 << st, 0);
            if (st == 0)
            {
                rv[st][0] = 0;
                continue;
            }
            int h = (1 << (st - 1));
            for(int k=0;k<( 1 << st);k++)
                rv[st][k] = (rv[st - 1][k & (h - 1)] << 1) | (k >= h);
        }
    }

    void ntt(vector<Mint> &d, bool inv = false)
    {
        int N = 1;
        int st=0;
        while (N < d.size()){
            N *= 2;
            st++;
        }
        //d.resize(N);
       
        for (int i = 0;i<N;i++)
        {
           if(i<rv[st][i]) swap(d[i],d[rv[st][i]]);
        }
        int tt=0;
        for (int len = 1; len * 2 <= N; len <<= 1)
        {
            tt++;
            for (int i = 0; i + len * 2 <= N; i += len * 2)
            {
                int dd = N / 2 / len;
                for (int j = 0; j < len; j++)
                {
                    Mint t = d[i + j + len] * w[tt][j];
                    d[i + j + len] = d[i + j] - t;
                    d[i + j] += t;
                }
            }
        }
        if (inv)
        {
            Mint invN = Mint::inv(N);
            for (int i = 0; i < N; i++)
                d[i] = d[i] * invN;
            reverse(d.begin()+1,d.end());
        }
        //return d;
    }
    vector<Mint> conv(vector<Mint> d1, vector<Mint> d2)
    {
        int num = d1.size() + d2.size() - 1;
        int cnt = 1 << (32 - __builtin_clz(num));
        d1.resize(cnt), d2.resize(cnt);
        ntt(d1);
        ntt(d2);
        vector<Mint> tmp(d1.size());
        for (int i = 0; i < d1.size(); i++)
            tmp[i] = d1[i] * d2[i];
        ntt(tmp, true);
        //r.resize(num);
        return tmp;
    }
} // namespace NTT

void solve(int caseNum)
{
    int n;
    cin >> n;
    vector<int> a(n), b(n);
    for (int i = 0; i < n; i++)
        cin >> a[i] >> b[i];
    vector<Mint> r(1, 1);
    auto inv = Mint::getInvArray(2e5);
    vector<Mint> P(2e5 + 1, 1);
    vector<Mint> IP(2e5 + 1, 1);
    for (int i = 2; i < P.size(); i++)
    {
        P[i] = P[i - 1] * i;
        IP[i] = IP[i - 1] * inv[i];
    }

    NTT::prepare();
    for (int i = 0; i < n; i++)
    {
        int s = max(0, b[i] - (int)r.size() + 1);
        int e = min(a[i] + (int)r.size() - 1, a[i] + b[i]);
        vector<Mint> x(e - s + 1);
        for (int j = s; j <= e; j++)
        {
            x[j - s] = P[a[i] + b[i]] * IP[j] * IP[a[i] + b[i] - j];
        }
        auto t = NTT::conv(r, x);
        int t1 = b[i] - s;
        int t2 = min(a[i] + (int)r.size() - 1 - s, (int)t.size() - 1);
        vector<Mint> res(t2-t1+1);
        for (int j = t1; j <= t2;j++)
        {
            res[j-t1]=t[j];
        }
        swap(r, res);
    }
    Mint sum;
    for (auto t : r)
        sum += t;
    cout << sum.v << endl;
}

int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.precision(10);
    int T = 1;
    //cin >> T;
    for (int i = 1; i <= T; i++)
    {
        solve(i);
    }
    cout.flush();
    return 0;
}
