#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vl = vector<ll>;
using vvl = vector<vl>;
using vb = vector<bool>;
using P = pair<ll, ll>;
template <typename T>
using pq = priority_queue<T>;
template <typename T>
using minpq = priority_queue<T, vector<T>, greater<T>>;
template <typename T, typename K>
using ump = unordered_map<T, K>;
const ll dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
const ll mod = 998244353;
const ll inf = ll(1e9);
const ll e5 = ll(1e5);
const ll ll_inf = ll(1e9) * ll(1e9);
template <class T>
ostream &operator<<(ostream &out, const vector<T> &list) {
  ll n = list.size();
  for (ll i = 0; i < (ll)(n); i++) out << list[i] << ' ';
  return out;
}
template <class T>
istream &operator>>(istream &in, vector<T> &list) {
  ll n = list.size();
  for (ll i = 0; i < (ll)(n); i++) in >> list[i];
  return in;
}
template <class T>
ostream &operator<<(ostream &out, const vector<vector<T>> &list) {
  ll n = list.size();
  for (ll i = 0; i < (ll)(n); i++) out << list[i] << '\n';
  return out;
}
template <typename Data, typename Lazy>
struct SegmentTree {
 public:
  bool isLazy = false;
  int sz;
  vector<Data> seg;
  vector<Lazy> lazy;
  using MergeData = function<Data(Data, Data)>;
  using UpdateLazyFromX = function<Lazy(Lazy, Lazy)>;
  using UpdateDataFromLazy = function<Data(Data, Lazy)>;
  using CalcLazyWithLen = function<Lazy(Lazy, ll)>;
  SegmentTree(int n, const MergeData fm, const UpdateLazyFromX fl,
              const UpdateDataFromLazy fa, const CalcLazyWithLen fw, Data M1,
              Lazy A1)
      : fm(fm), fl(fl), fa(fa), fw(fw), M1(M1), A1(A1) {
    isLazy = true;
    sz = 1;
    while (sz < n) sz *= 2;
    seg.assign(2 * sz - 1, M1);
    lazy.assign(2 * sz - 1, A1);
  }
  SegmentTree(int n, const MergeData fm, Data M1)
      : fm(fm),
        M1(M1),
        fl([M1](Data a, Data b) { return M1; }),
        fa([M1](Data a, Lazy b) { return M1; }),
        fw([M1](Lazy a, ll b) { return M1; }),
        A1(M1) {
    isLazy = false;
    sz = 1;
    while (sz < n) sz *= 2;
    seg.assign(2 * sz - 1, M1);
  }
  Data update(int i, Data x) {
    i += sz - 1;
    seg[i] = x;
    while (i > 0) {
      i = (i - 1) / 2;
      seg[i] = fm(seg[2 * i + 1], seg[2 * i + 2]);
    }
  }
  void build(const vector<Data> &v) {
    ll n = v.size();
    for (ll i = 0; i < (ll)(n); i++) seg[i + sz - 1] = v[i];
    for (ll i = sz - 2; i >= 0; --i) {
      seg[i] = fm(seg[i * 2 + 1], seg[i * 2 + 2]);
    }
  }
  Data update(int a, int b, Data x) { return update(a, b, x, 0, 0, sz); }
  Data query(int a, int b) { return query(a, b, 0, 0, sz); }

 private:
  const MergeData fm;
  const UpdateLazyFromX fl;
  const UpdateDataFromLazy fa;
  const CalcLazyWithLen fw;
  const Data M1;
  const Lazy A1;
  void eval(int len, int k) {
    if (lazy[k] == A1) return;
    if (k * 2 + 1 < sz * 2 - 1) {
      lazy[2 * k + 1] = fl(lazy[2 * k + 1], lazy[k]);
      lazy[2 * k + 2] = fl(lazy[2 * k + 2], lazy[k]);
    }
    seg[k] = fa(seg[k], fw(lazy[k], len));
    lazy[k] = A1;
  }
  Data update(int a, int b, Data x, int k, int l, int r) {
    eval(r - l, k);
    if (r <= a || b <= l) return seg[k];
    if (a <= l && r <= b) {
      lazy[k] = fl(lazy[k], x);
      return fa(seg[k], fw(lazy[k], r - l));
    }
    return seg[k] = fm(update(a, b, x, k * 2 + 1, l, (l + r) / 2),
                       update(a, b, x, k * 2 + 2, (l + r) / 2, r));
  }
  Data query(int a, int b, int k, int l, int r) {
    if (isLazy) eval(r - l, k);
    if (r <= a || b <= l) return M1;
    if (a <= l && r <= b) return seg[k];
    Data vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
    Data vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
    return fm(vl, vr);
  }
};
SegmentTree<ll, ll> RangeMinimumTree(int n) {
  auto fm = [](ll a, ll b) { return min(a, b); };
  auto fl = [](ll a, ll b) { return b; };
  auto fa = [](ll a, ll b) { return b; };
  auto fw = [](ll a, ll w) { return a; };
  SegmentTree<ll, ll> tree(n, fm, fl, fa, fw, LONG_MAX, LONG_MAX);
  return tree;
}
SegmentTree<ll, ll> RangeMaxTree(int n) {
  auto fm = [](ll a, ll b) { return max(a, b); };
  auto fl = [](ll a, ll b) { return b; };
  auto fa = [](ll a, ll b) { return b; };
  auto fw = [](ll a, ll w) { return a; };
  SegmentTree<ll, ll> tree(n, fm, fl, fa, fw, LONG_MIN, LONG_MIN);
  return tree;
}
SegmentTree<ll, ll> RangeSumTree(int n) {
  auto fm = [](ll a, ll b) { return (a + b) % mod; };
  auto fl = [](ll a, ll b) { return (a + b) % mod; };
  auto fa = [](ll a, ll b) { return (a + b) % mod; };
  auto fw = [](ll a, ll w) { return (a * w) % mod; };
  SegmentTree<ll, ll> tree(n, fm, fl, fa, fw, 0, 0);
  return tree;
}
void solve() {
  ll n, k;
  cin >> n >> k;
  SegmentTree<ll, ll> tree = RangeSumTree(n + 1);
  vl imos(n + 2);
  for (ll i = 0; i < (ll)(k); i++) {
    ll l, r;
    cin >> l >> r;
    imos[l]++, imos[r + 1]--;
  }
  ll cnt = 0;
  ll start = 0;
  vector<P> lrs;
  for (ll i = 0; i < (ll)(n + 1); i++) {
    if (cnt == 0 && imos[i] > 0) start = i;
    ll newCnt = cnt + imos[i];
    if (cnt > 0 && newCnt == 0) lrs.emplace_back(P{start, i - 1});
    cnt = newCnt;
  }
  tree.update(0, 1, 1);
  for (ll i = 0; i < (ll)(n); i++) {
    for (auto &e : lrs) {
      ll l = i + e.first, r = i + e.second;
      if (l > n - 1) continue;
      r = min(n - 1, r);
      tree.update(l, r + 1, tree.query(i, i + 1));
    }
  }
  cout << tree.query(n - 1, n) << '\n';
}
int main() {
  solve();
  return 0;
}
