#include <bits/stdc++.h>
using namespace std;

constexpr int64_t MOD= 998244353;
constexpr bool is_FACTORIAL_STORED= false; // 階乗を配列に格納をする前処理をする/しない
constexpr int Nfac= is_FACTORIAL_STORED ? 2000007
                                        : 0;
/* 剰余環 Z/nZ */
struct mint{ // Z/nZ に関する演算(n:素数の場合は除算も)をサポートする構造体
  int64_t rep; // 出力すべき代表元 rep \in {0,1,..,MOD- 1}
  mint(int64_t x=0): rep(((x%MOD)+ MOD)% MOD){}
  mint operator-() const { return mint(-rep);}
  mint& operator+=(const mint& x){
    rep+= x.rep; 
    if(rep>= MOD) rep-= MOD;
    return *this;
  }
  mint& operator-=(const mint& x){
    rep-= x.rep;
    if(rep< 0) rep+= MOD;
    return *this;
  }
  mint& operator*=(const mint& x){
    rep*= x.rep; rep%= MOD;
    return *this;
  }
  mint operator+(const mint x) const {
    mint ans(*this);
    ans+= x;
    return ans;
  }
  mint operator-(const mint x) const {
    mint ans(*this);
    ans-= x;
    return ans;
  }
  mint operator*(const mint x) const {
    mint ans(*this);
    ans*= x;
    return ans;
  }
  bool operator==(const mint x) const {
    return rep==x.rep;
  }
  bool operator!=(const mint x) const {
    return rep!=x.rep;
  }

  mint pow(int64_t d) const{ // d \geq 0
    mint ans= 1;
    mint x= *this;
    while(d > 0){
      if(d&1){ ans*= x; }
      d >>= 1;
      x*= x;
    }

    return ans;
  }

  friend istream& operator >> (istream &is, mint& x) noexcept{
    int64_t a;
    is >> a;
    x= a;
    return is;
  }
  friend ostream& operator << (ostream &os, const mint& x) noexcept{
      return os << x.rep;
  }
  // MOD が素数(<=> Z/nZ が体)のとき
  mint inv() const{
    return pow(MOD-2);
  }
  mint& operator/=(const mint& x){
    *this *= x.inv();
    return *this;
  }
  mint operator/(const mint x) const {
    mint ans(*this);
    ans/= x;
    return ans;
  }
};

template <typename T>
struct SegmentTree{
  T m_id;
  T op(const T &a, const T &b) const{
    return max(a, b);
  }
  vector<T> m_SegT;

  SegmentTree(int N): m_id(numeric_limits<T>::min()), m_SegT(2*N, m_id){}
  SegmentTree(const vector<T> &data): m_id(numeric_limits<T>::min()), m_SegT(2*data.size()){
    int N= m_SegT.size() >> 1;
    for(int i=0; i<N; i++){
      m_SegT.at(i+N)= data.at(i);
    }
    for(int i=N-1; i>0; i--){
      m_SegT.at(i)= op(m_SegT.at(i << 1), m_SegT.at((i << 1) | 1));
    }
  }

  void set_val(int idx, T val){
    idx+= m_SegT.size() >> 1;
    m_SegT.at(idx)= val;
    while((idx >> 1) > 0){
      idx >>= 1;
      m_SegT.at(idx)= op(m_SegT.at(idx << 1), m_SegT.at((idx << 1) | 1));
    }
  }

  T range(int left, int right) const{// [left, right)
    left += m_SegT.size() >> 1;
    right+= m_SegT.size() >> 1;
    T calc_l= m_id;
    T calc_r= m_id;

    while(left < right){
      if(left&1){
        calc_l= op(calc_l, m_SegT.at(left));
        left++;
      }
      if(right&1){
        calc_r= op(m_SegT.at(right-1), calc_r);
      }

      left >>= 1;
      right>>= 1;
    }

    return op(calc_l, calc_r);
  }
};

int main(){
  using pii= pair<int, int>;
  int N;
  cin >> N;

  vector<pii> data(N);
  int pos,reach;
  for(int i=0; i<N; i++){
    cin >> pos >> reach;
    data.at(i)= make_pair(pos, pos+ reach);
  }
  sort(data.begin(), data.end());

  vector<mint> dp(N+1);
  dp.back()= 1;
  SegmentTree<int> idx(N);
  for(int left=N-1; left >= 0; left--){
    auto itr_right= upper_bound(data.begin()+ left, data.end(), make_pair(data.at(left).second, INT_MIN));
    int right= distance(data.begin(), itr_right);
    int id_off= left+ 1;
    int id_on = max(id_off, idx.range(left, right));
    idx.set_val(left, id_on);

    dp.at(left)= dp.at(id_off)+ dp.at(id_on);
  }
  mint ans= dp.at(0);
  
  cout << ans << endl;
}

Measured memory_bytes: 4992