#include <bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp> 
#include <ext/pb_ds/tree_policy.hpp> 
using namespace __gnu_pbds; 
#pragma GCC target ("avx2")
#pragma GCC optimization ("O3")
#pragma GCC optimization ("unroll-loops")
#define fi first
#define se second
#define endl '\n'
// #define int int64_t
#define double long double
template<typename T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
template<typename T> using reverse_queue = priority_queue<T, vector<T>, greater<T>>;
mt19937_64 rnd(time(0));
const int64_t FIXED_RANDOM = rnd();
template<typename T> struct custom_hash{T operator()(T x)const{return (T) x^FIXED_RANDOM;}}; // check hash in whether int64 or int32
template<typename T1, typename T2> using hash_map = gp_hash_table<T1, T2, custom_hash<T1>>;
// Tao luyện kỹ thuật trong 8 năm mày luyện kỹ thuật trong buồng tắm nam
const int MAXN = (int) 2e5 + 2;
const int INF = numeric_limits<int>::max() >> 1;
const int MOD = (int) 998244353;
int Add(int a, int b){a+=b;a%=MOD;return a<0?a+MOD:a;}
struct lazy_segment_tree{
  using it_type = long long;
  int32_t n;
  vector<it_type> it;
  vector<long long> lz;
  const it_type FAILED_STAGE = 0;
  void init(int _){
    n = _;
    it.resize((n << 2)|1);
    lz.resize((n << 2)|1);
  }
  it_type merge(it_type a, it_type b){
    return Add(a, b);
  }
  it_type build(int32_t u, int32_t l, int32_t r, auto &a){ // 1 indexed
    if(l == r) return it[u] = (1LL << (a[l] - 1));
    return it[u] = merge(build(u << 1, l, ((l + r)>>1), a), build((u << 1)|1, ((l + r)>>1) + 1, r, a)); // merge stage
  }
  void lazy(int32_t u, int32_t l, int32_t r){ // lazy 
    if(lz[u] == 0) return;
    it[u] = Add(it[u], lz[u]);
    if(l != r){
      lz[u << 1] = Add(lz[u], lz[u << 1]);
      lz[(u << 1)|1] = Add(lz[u], lz[(u << 1)|1]);
    }
    lz[u] = 0;
  }
  void update(int32_t u, int32_t l, int32_t r, int32_t L, int32_t R, int val){
    if(R < L) return;
    lazy(u, l, r);
    if(l > R || r < L) return;
    if(L <= l && r <= R){
      lz[u] = val; // lazy update 
      lazy(u, l, r);
      return;
    }
    update(u << 1, l, ((l + r)>>1), L, R, val);
    update((u << 1)|1, ((l + r)>>1) + 1, r, L, R, val);
    it[u] = merge(it[u << 1], it[(u << 1)|1]); // merge stage
  }
  it_type get(int32_t u, int32_t l, int32_t r, int32_t L, int32_t R){
    if(l > R || r < L) return FAILED_STAGE; // check for failed stage
    lazy(u, l, r);
    if(L <= l && r <= R) return it[u];
    return merge(get(u << 1, l, ((l + r)>>1), L, R), get((u << 1)|1, ((l + r)>>1) + 1, r, L, R)); // merge stage
  }
};
signed main(){
  ios_base::sync_with_stdio(0); 
  cin.tie(0);
  // freopen("FDT.txt", "r", stdin);
  int n, k;
  cin >> n >> k;
  vector<int> l(k), r(k);
  for(int i = 0; i < k; i ++) cin >> l[i] >> r[i];
  lazy_segment_tree tree;
  tree.init(n);
  tree.update(1, 1, n, 1, 1, 1);
  for(int i = 1; i < n; i ++){
    int cur = tree.get(1, 1, n, i, i);
    // cout << "ways " << i << ": " << cur << endl;
    for(int j = 0; j < k; j ++){
      if(i + l[j] > n) continue;
      // cout << "from " << i << "-> " << min(i + l[j], n) << " " << min(i + r[j], n) << endl;
      // d + l[j] -> d + r[j] + 1
      tree.update(1, 1, n, min(i + l[j], n), min(i + r[j], n), cur);
    }
  }
  cout << tree.get(1, 1, n, n, n);
}

Measured memory_bytes: 15852