//
//  main.cpp
//

#include <algorithm>
#include <array>
#include <assert.h>
#include <complex>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <math.h>
#include <memory>
#include <memory>
#include <queue>
#include <random>
#include <set>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>

using namespace std;

using ll = int64_t;
using ull = uint64_t;
constexpr ll LL_MAX = numeric_limits<ll>::max();
constexpr ull ULL_MAX = numeric_limits<ull>::max();

template<typename T>
vector<T> make_vec_nd(T init, ll size) {
	return vector<T>(size, init);
}
template<typename T, typename... Args>
auto make_vec_nd(T init, ll size, Args... rest) {
	auto inner = make_vec_nd(init, rest...);
	return vector<decltype(inner)>(size, inner);
}

#define rep(i, a, b) for (ll i = (a); i < (b); i++)
#define rrep(i, a, b) for (ll i = (a)-1; i >= (b); i--)

// 素因数分解
unordered_map<ll, ll> prime_factorization(ll num) {
    unordered_map<ll, ll> ans;
    ll p = 2;
    while (p * p <= num) {
        if (num % p == 0) {
            ans[p]++;
            num /= p;
        } else {
            p++;
        }
    }
    if (num > 1) {
        ans[num]++;
    }
    return ans;
}

struct Mod {
    static thread_local uint64_t PRIME;
    struct LocalPrime {
        uint64_t backup;
        LocalPrime(uint64_t prime) { backup = exchange(Mod::PRIME, prime); }
        ~LocalPrime() { Mod::PRIME = backup; }
    };
    uint64_t value = 0;
    Mod()
    : value(0) {}
    Mod(ll v) {
        if (v >= 0) {
            value = v % PRIME;
        } else {
            value = PRIME - (-v) % PRIME;
        }
    }
    Mod operator+(const Mod& rhs) const { return Mod(*this) += rhs; }
    Mod& operator+=(const Mod& rhs) {
        value += rhs.value;
        if (value >= PRIME) {
            value -= PRIME;
        }
        return *this;
    }
    Mod operator-(const Mod& rhs) const { return Mod(*this) -= rhs; }
    Mod& operator-=(const Mod& rhs) {
        if (value < rhs.value) {
            value += PRIME;
        }
        value -= rhs.value;
        return *this;
    }
    Mod operator*(const Mod& rhs) const { return Mod(*this) *= rhs; }
    Mod& operator*=(const Mod& rhs) {
        value = (value * rhs.value) % PRIME;
        return *this;
    }
    Mod inv() const { return power(*this, PRIME - 2); }
    Mod operator/(const Mod& rhs) const { return Mod(*this) /= rhs; }
    Mod& operator/=(const Mod& rhs) {
        *this *= rhs.inv();
        return *this;
    }
    static Mod power(Mod rhs, ll exp) {
        Mod ans = 1;
        while (exp > 0) {
            if (exp % 2) {
                ans *= rhs;
            }
            rhs *= rhs;
            exp /= 2;
        }
        return ans;
    }
    // fact - nullable
    static bool is_root_of_unity(int64_t x, uint64_t prime, unordered_map<ll, ll>* fact) {
        unordered_map<ll, ll> fact_val;
        if (fact == nullptr) {
            fact_val = prime_factorization(prime - 1);
            fact = &fact_val;
        }
        LocalPrime local(prime);
        for (auto& kv : *fact) {
            uint64_t p = kv.first;
            if (power(Mod(x), (prime - 1) / p).value == 1) {
                return false;
            }
        }
        return true;
    }
    static ll root_of_unity(uint64_t prime) {
        LocalPrime local(prime);
        unordered_map<ll, ll> fact = prime_factorization(prime - 1);
        for (ll x = 1; x < prime; x++) {
            if (is_root_of_unity(x, prime, &fact)) {
                return x;
            }
        }
        assert(false);
        return 0;
    }
};
thread_local uint64_t Mod::PRIME = 998244353;

template<typename Monoid>
struct SegmentTree {
    using Op = function<Monoid(const Monoid& lhs, const Monoid& rhs)>;
    ll width;
    vector<Monoid> node;
    Op op;
    Monoid unit;
    
    SegmentTree(ll N, Op op, Monoid unit)
    : SegmentTree(vector<Monoid>(N, unit), op, unit) {}
    SegmentTree(const vector<Monoid>& elems, Op op, Monoid unit)
    : op(op)
    , unit(unit) {
        width = 1;
        while (width < elems.size()) {
            width *= 2;
        }
        node.resize(2 * width - 1, unit);
        for (size_t i = 0; i < elems.size(); i++) {
            node[i + width - 1] = elems[i];
        }
        for (size_t i = width - 2; i != numeric_limits<size_t>::max(); i--) {
            node[i] = op(node[2 * i + 1], node[2 * i + 2]);
        }
    }
    void update(ll idx, Monoid elem) {
        idx += width - 1;
        node[idx] = elem;
        while (idx >= 1) {
            idx = (idx - 1) / 2;
            node[idx] = op(node[2 * idx + 1], node[2 * idx + 2]);
        }
    }
    Monoid query(ll a, ll b, ll root = 0) const {
        assert(0 <= a && b <= width);
        ll left = root, right = root;
        while (left < width - 1) {
            left = 2 * left + 1;
        }
        left -= (width - 1);
        while (right < width - 1) {
            right = 2 * right + 2;
        }
        right -= (width - 1);
        right++;
        if (right <= a || b <= left) {
            return unit;
        }
        if (a <= left && right <= b) {
            return node[root];
        }
        Monoid ans_l = query(a, b, 2 * root + 1);
        Monoid ans_r = query(a, b, 2 * root + 2);
        return op(ans_l, ans_r);
    }
    Monoid operator[](size_t idx) { return query(idx, idx + 1); }
};

int main() {
    ll N;
    cin >> N;
    struct Robot {
        ll X;
        ll D;
    };
    vector<Robot> robots(N);
    rep(i,0,N) {
        cin >> robots[i].X >> robots[i].D;
    }
    sort(robots.begin(), robots.end(), [](Robot& lhs, Robot& rhs){
        return lhs.X < rhs.X;
    });
    SegmentTree<ll> tree(vector<ll>(N, numeric_limits<ll>::min()), [](ll lhs, ll rhs){
        return max(lhs, rhs);
    }, numeric_limits<ll>::min());
    tree.update(N-1, N);
    rrep(i,N-1,0) {
        auto end = partition_point(robots.begin() + i, robots.end(), [i, &robots](const Robot& r) {
            return r.X < robots[i].X + robots[i].D;
        });
        ll end_i = distance(robots.begin(), end);
        ll val = tree.query(i, end_i);
        val = max(val, end_i);
        tree.update(i, val);
    }
    vector<Mod> ans(N+1);
    ans[N] = 1;
    rrep(i,N,0) {
        // 起動しないとき
        ans[i] += ans[i+1];
        // 起動するとき
        ll idx = tree[i];
        ans[i] += ans[idx];
    }
    cout << ans[0].value << endl;
}


/*
 
 2
 1 2
 3 3
 
 3
 1 2
 2 2
 3 1
 
 3
 1 1
 2 1
 3 1
 
 3
 1 3
 2 1
 3 1
 
 3
 1 2
 2 1
 3 1
 
 */


Measured memory_bytes: 9088