/**
 * Dont raise your voice, improve your argument.
 * --Desmond Tutu
 */

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

const bool ready = [](){
    ios_base::sync_with_stdio(false); cin.tie(0);
    cout << fixed << setprecision(12);
    return true;
}();

const double PI = acos(-1);
using ll= long long;
#define int ll
#define all(v) (v).begin(), (v).end()
#define fori(n) for(int i=0; i<int(n); i++)

#define cini(i) int i; cin>>i;
#define cins(s) string s; cin>>s;
#define cind(d) double d; cin>>d;
#define cinai(a,n) vi a(n); fori(n) { cin>>a[i]; }
#define cinas(s,n) vs s(n); fori(n) { cin>>s[i]; }
#define cinad(a,n) vd a(n); fori(n) { cin>>a[i]; }

using pii= pair<int, int>;
using pdd= pair<double, double>;
using vd= vector<double>;
using vb= vector<bool>;
using vi= vector<int>;
using vvi= vector<vi>;
using vs= vector<string>;

#define endl "\n"


template<typename E>
struct SegmentTreeLazy {
    vector<E> data;
    vector<E> lazyInc;
    vector<bool> lazyIncB;  /* flag if there is a pending lazyInc in node */
    vector<E> lazySet;
    vector<bool> lazySetB;  /* flag if there is a pending lazySet in node */

    E neutral;
    int n;

    function<E(E,E)> plus;
    function<E(E,int)> mult;

    SegmentTreeLazy(int _n, E _neutral) {
        n=1;
        while(n<_n)
            n*=2;

        data.resize(n*2, _neutral);
        lazyInc.resize(n*2, _neutral);
        lazyIncB.resize(n*2);
        lazySet.resize(n*2, _neutral);
        lazySetB.resize(n*2);
        neutral=_neutral;
    }

    /* bulk update in O(n) */
    template<typename Iterator>
    void init(Iterator beg, Iterator end) {
        for(int idx=n; beg!=end; beg++, idx++)
            data[idx]=*beg;

        for(int idx=n-1; idx>=1; idx--)
            data[idx]=plus(data[idx*2], data[idx*2+1]);
    }

    /* pushes down the pending updates to the vertex node 
     * If both lazies are set then the inc was later, so both
     * have to be pushed.
     * But first the set, which erases all previously set 
     * and inc on the child nodes, then the inc.
     * */
    void pushlazy(int node, int sL, int sR) {
        if(lazySetB[node]) {
            //cerr<<"pushlazy Set, node="<<node<<" sL="<<sL<<" sR="<<sR<<endl;

            if(sL!=sR) {
                int mid=(sL+sR)/2;
                rangeSet(node*2, sL   , mid, sL   , mid, lazySet[node]);
                rangeSet(node*2+1, mid+1, sR , mid+1, sR , lazySet[node]);
            }

            lazySetB[node]=false;
            lazySet[node]=neutral;
        }

        if(lazyIncB[node]) {
            //cerr<<"pushlazy Inc, node="<<node<<" sL="<<sL<<" sR="<<sR<<endl;
            if(sL!=sR) {
                int mid=(sL+sR)/2;
                rangeInc(node*2, sL   , mid, sL   , mid, lazyInc[node]);
                rangeInc(node*2+1, mid+1, sR , mid+1, sR , lazyInc[node]);
            }
            lazyIncB[node]=false;
            lazyInc[node]=neutral;
        }
    }

    /* @return accumulative (l,r), both inclusive, top down */
    E query(int node, int sL, int sR, int l, int r) {
        if (r < sL || l > sR)
            return neutral;
        //cerr<<"query, node="<<node<<" sL="<<sL<<" sR="<<sR<<" l="<<l<<" r="<<r<<" data[node]="<<data[node]<<endl;

        if (l<=sL && r>=sR)
            return data[node];

        pushlazy(node, sL, sR);

        int mid = (sL+sR)/2;
        return plus(query(node*2, sL, mid, l, r), query(node*2+1, mid+1, sR, l, r));
    }
    E query(int l, int r) {
        return query(1, 0, n-1, l, r);
    }

    /* set all position in (l,r) to val */
    void rangeSet(int node, int sL, int sR, int l, int r, E val) {
        if (r < sL || l > sR)
            return;
        //cerr<<"rangeSet node="<<node<<" sL="<<sL<<" sR="<<sR<<" l="<<l<<" r="<<r<<" val="<<val<<endl;

        if(l<=sL && r>=sR) {
            lazySet[node]=val;
            lazyInc[node]=neutral;
            lazySetB[node]=true;
            lazyIncB[node]=false;
            data[node]=mult(val, sR-sL+1);
            //cerr<<"rangeSet did set node="<<data[node]<<endl;
            return;
        }

        pushlazy(node, sL, sR);

        int mid = (sL+sR)/2;
        rangeSet(node*2  , sL   , mid, l, r, val);
        rangeSet(node*2+1, mid+1, sR , l, r, val);
        data[node]=plus(data[node*2], data[node*2+1]);
    }

    /* set val at positions (l,r) */
    void rangeSet(int l, int r, E val) {
        rangeSet(1, 0, n-1, l, r, val);
    }

    /* increment all position in (l,r) by inc */
    void rangeInc(int node, int sL, int sR, int l, int r, E inc) {
        if (r < sL || l > sR)
            return;
        //cerr<<"rangeInc node="<<node<<" sL="<<sL<<" sR="<<sR<<" l="<<l<<" r="<<r<<" val="<<inc<<endl;

        if(l<=sL && r>=sR) {
            lazyInc[node]+=inc;
            lazyIncB[node]=true;
            data[node]+=mult(inc, sR-sL+1);
            //cerr<<"rangeInc did set node="<<data[node]<<endl;
            return;
        }

        pushlazy(node, sL, sR);

        int mid = (sL+sR)/2;
        rangeInc(node*2  , sL   , mid, l, r, inc);
        rangeInc(node*2+1, mid+1, sR , l, r, inc);
        data[node]=plus(data[node*2], data[node*2+1]);
    }

    /* increment by inc at positions (l,r) */
    void rangeInc(int l, int r, E inc) {
        rangeInc(1, 0, n-1, l, r, inc);
    }
};

/* some wiered dp...
 *
 *
 */
void solve() {
    cini(n);
    cini(k);
    vi l(k);
    vi r(k);
    for(int i=0; i<k; i++) 
        cin>>l[i]>>r[i];

    const int MOD=998244353;
    SegmentTreeLazy<int> seg(n+1, 0);
    seg.plus=[](int i1, int i2) { return (i1+i2)%MOD; };
    seg.mult=[](int i1, int i2) { return (i1*i2)%MOD; };

    seg.rangeSet(1,1,1);

    for(int i=0; i<n; i++) {
        const int val=seg.query(i,i);
        if(val==0)
            continue;

        for(int j=0; j<k; j++)
            seg.rangeInc(i+l[j], i+r[j], val);
    }

    int ans=seg.query(n, n);
    cout<<ans<<endl;

}

signed main() {
    solve();
}

// FIRST THINK, THEN CODE
// DO NOT JUMP BETWEEN PROBLEMS


Measured memory_bytes: 15868