#include <bits/stdc++.h>
#define rep(a,n) for (ll a = 0; a < (n); ++a)
using namespace std;
using ll = long long;
typedef pair<ll,ll> P;
typedef pair<ll,P> PP;
typedef vector<vector<ll> > Graph;
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
const ll INF = 1e18;

// auto mod int
// depends on Template

//const int mod = 1000000007;
const int mod = 998244353;
struct mint {
  ll x; // typedef long long ll;
  mint(ll x=0):x((x%mod+mod)%mod){}
  mint operator-() const { return mint(-x);}
  mint& operator+=(const mint a) {
    if ((x += a.x) >= mod) x -= mod;
    return *this;
  }
  mint& operator-=(const mint a) {
    if ((x += mod-a.x) >= mod) x -= mod;
    return *this;
  }
  mint& operator*=(const mint a) { (x *= a.x) %= mod; return *this;}
  mint operator+(const mint a) const { return mint(*this) += a;}
  mint operator-(const mint a) const { return mint(*this) -= a;}
  mint operator*(const mint a) const { return mint(*this) *= a;}
  mint pow(ll t) const {
    if (!t) return 1;
    mint a = pow(t>>1);
    a *= a;
    if (t&1) a *= *this;
    return a;
  }

  // for prime mod
  mint inv() const { return pow(mod-2);}
  mint& operator/=(const mint a) { return *this *= a.inv();}
  mint operator/(const mint a) const { return mint(*this) /= a;}
};
istream& operator>>(istream& is, const mint& a) { return is >> a.x;}
ostream& operator<<(ostream& os, const mint& a) { return os << a.x;}

long long modpow(long long a, long long n) {
    long long res = 1;
    while (n > 0) {
        if (n & 1) res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}


template<typename T,typename M>
struct SegTree{
    using FX = function<T(T,T)>;//T●T->Tとなる関数の型
    using FA = function<T(T,M)>;
    using FM = function<M(M,M)>;
    using FP = function<M(M,ll)>;
    ll n;
    FX fx;
    FA fa;
    FM fm;
    FP fp;
    const T ex;//単位元
    const M em;
    vector<T> node;
    vector<M> lazy;
    SegTree(ll n_, FX fx_, FA fa_,FM fm_, FP fp_ ,T ex_,M em_)
        : n(),fx(fx_),fa(fa_),fm(fm_),fp(fp_),ex(ex_),em(em_),node(n_*4,ex),lazy(n_*4,em){
        ll x = 1;
        while(n_>x)x*=2;
        n=x;
    }

    void set(ll i,T x){
        node[i+n-1] = x;
    }

    void build(){
        for(ll k=n-2;k>=0;k--)node[k]=fx(node[2*k+1],node[2*k+2]);
    }

    void eval(ll k,ll len){
        if(lazy[k]==em)return;//更新がなければ終了
        if(k<n-1){//葉でなければ子に伝搬
            lazy[k*2+1]=fm(lazy[k*2+1],lazy[k]);
            lazy[k*2+2]=fm(lazy[k*2+2],lazy[k]);
        }
        //自身の更新
        node[k]=fa(node[k],fp(lazy[k],len));
        lazy[k]=em;
    }

    void update(ll a, ll b, M x, ll k, ll l, ll r){
        eval(k,r-l);
        if(a<=l&&r<=b){  //完全に内側
            lazy[k]=fm(lazy[k],x);
            eval(k,r-l);
        }
        else if(a<r && l<b){  //一部区間がかぶる
            update(a,b,x,k*2+1,l,(l+r)/2);
            update(a,b,x,k*2+2,(l+r)/2,r);
            node[k]=fx(node[k*2+1],node[k*2+2]);
        }
    }

    void update(ll a,ll b,M x){
        update(a,b,x,0,0,n);
    }

    T query_sub(ll a,ll b,ll k,ll l,ll r){
        eval(k,r-l);
        if(r<=a || b<=l){
            return ex;
        }
        else if(a<=l && r<=b){
            return node[k];
        }
        else{
            T vl = query_sub(a,b,k*2+1,l,(l+r)/2);
            T vr = query_sub(a,b,k*2+2,(l+r)/2,r);
            return fx(vl,vr);
        }
    }

    T query(ll a,ll b){
        return query_sub(a,b,0,0,n);
    }

    T operator[](ll i){
        return query(i,i+1);
    }

    void print(){//デバッグ用
        for(ll i=0;i<n;i++){
            cout << (*this)[i];
            if(i != n-1)cout << ',';
        }
        cout << endl;
    }

    //二分探索で[a,b)でx以下の値を持つ最右の要素位置を見つける
    //コメントアウトするとx以上にもできる
    //全てx以下なら-1を返す
    //後々抽象化出来たらいいな
    ll find_right(ll a,ll b,ll x,ll k,ll l,ll r){
        eval(k,r-l);
        if(node[k]>x||r<=a||b<=l)return -1;
        //if(node[k]<x||r<=a||b<=l)return -1;
        if(k>=n-1)return (k-(n-1));
        ll rv = find_right(a,b,x,2*k+2,(l+r)/2,r);
        if(rv!=-1)return rv;
        return find_right(a,b,x,2*k+1,l,(l+r)/2);
    }

    ll find_right(ll a,ll b,ll x){
        return find_right(a,b,x,0,0,n);
    }

    //二分探索で[a,b)でx以下の値を持つ最左の要素位置を見つける
    //コメントアウトするとx以上にもできる
    //全てx以下なら-1を返す
    ll find_left(ll a,ll b,ll x,ll k,ll l,ll r){
        eval(k,r-l);
        if(node[k]>x||r<=a||b<=l)return -1;
        //if(node[k]<x||r<=a||b<=l)return -1;
        if(k>=n-1)return (k-(n-1));
        ll lv = find_left(a,b,x,2*k+1,l,(l+r)/2);
        if(lv!=-1)return lv;
        return find_left(a,b,x,2*k+2,(l+r)/2,r);
    }

    ll find_left(ll a,ll b,ll x){
        return find_left(a,b,x,0,0,n);
    }
};


int main(){
    ll n,k;
    cin >> n >> k;
    vector<P>vec(k);
    rep(i,k){
        ll l,r;
        cin >> l >> r;
        vec[i]={l,r};
    }
    using X = long long;
    using M = long long;
    auto fx = [](X x1, X x2) -> X { return x1 + x2; };
    auto fa = [](X x, M m) -> X { return (x + m)%mod; };
    auto fm = [](M m1, M m2) -> M { return (m1 + m2)%mod; };
    auto fp = [](M m, long long n) -> M { return m * n; };
    long long ex = 0;
    long long em = 0;
    SegTree<X, M> seg(n, fx, fa, fm, fp, ex, em);
    seg.set(0,1);
    seg.build();
    rep(i,n){
        ll now = seg[i];
        rep(j,k){
            ll l = vec[j].first+i;
            ll r = vec[j].second+i;
            if(l<=i)continue;
            r=min(r,n-1);
            seg.update(l,r+1,now);
        }
    }
    cout << seg[n-1] << endl;

    return 0;
}

Measured memory_bytes: 15588