Problem:
Score : 400 points

Problem Statement

There are N cells arranged in a row, numbered 1, 2, \ldots, N from left to right.

Tak lives in these cells and is currently on Cell 1. He is trying to reach Cell N by using the procedure described below.

You are given an integer K that is less than or equal to 10, and K non-intersecting segments [L_1, R_1], [L_2, R_2], \ldots, [L_K, R_K].
Let S be the union of these K segments.
Here, the segment [l, r] denotes the set consisting of all integers i that satisfy l \leq i \leq r.

When you are on Cell i, pick an integer d from S and move to Cell i + d. You cannot move out of the cells.

To help Tak, find the number of ways to go to Cell N, modulo 998244353.

Constraints

2 \leq N \leq 2 \times 10^5

1 \leq K \leq \min(N, 10)

1 \leq L_i \leq R_i \leq N

[L_i, R_i] and [L_j, R_j] do not intersect (i \neq j)

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N K
L_1 R_1
L_2 R_2
:
L_K R_K

Output

Print the number of ways for Tak to go from Cell 1 to Cell N, modulo 998244353.

Sample Input 1

5 2
1 1
3 4

Sample Output 1

4

The set S is the union of the segment [1, 1] and the segment [3, 4], therefore S = \{ 1, 3, 4 \} holds.

There are 4 possible ways to get to Cell 5:

1 \to 2 \to 3 \to 4 \to 5,

1 \to 2 \to 5,

1 \to 4 \to 5 and

1 \to 5.

Sample Input 2

5 2
3 3
5 5

Sample Output 2

0

Because S = \{ 3, 5 \} holds, you cannot reach to Cell 5.
Print 0.

Sample Input 3

5 1
1 2

Sample Output 3

5

Sample Input 4

60 3
5 8
1 3
10 15

Sample Output 4

221823067

Note that you have to print the answer modulo 998244353.

Solution in C++ (GCC 9.2.1) (judge verdict: Accepted)

#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
//#include<boost/multiprecision/cpp_int.hpp>
//#include<boost/multiprecision/cpp_dec_float.hpp>
//namespace mp=boost::multiprecision;
//#define mulint mp::cpp_int
//#define mulfloat mp::cpp_dec_float_100
using namespace std;
struct __INIT{__INIT(){cin.tie(0);ios::sync_with_stdio(false);cout<<fixed<<setprecision(15);}} __init;
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
//constexpr int MOD=1000000007;
constexpr int MOD=998244353;
#define INF (1<<30)
#define LINF (lint)(1LL<<56)
#define endl "\n"
#define rep(i,n) for(lint (i)=0;(i)<(n);(i)++)
#define reprev(i,n) for(lint (i)=(n-1);(i)>=0;(i)--)
#define Flag(x) (1<<(x))
#define Flagcount(x) __builtin_popcountll(x)
#define pint pair<int,int>
#define pdouble pair<double,double>
#define plint pair<lint,lint>
#define fi first
#define se second
typedef long long lint;
int dx[8]={1,1,0,-1,-1,-1,0,1};
int dy[8]={0,1,1,1,0,-1,-1,-1};
const int MAX_N=2e5+5;
//struct edge{lint to,num;};
//vector<int> bucket[MAX_N/1000];

lint segdata[(1<<19)-1];
lint lazy[(1<<19)-1];

lint neutral(){
    return 0; //単位元
}
lint calc(lint a,lint b){
    return (a+b)%MOD; //演算
}
void seginit(){
    rep(i,(1<<19)-1) segdata[i]=neutral();
}
void update(lint i,lint x){ // i番目の値をxに更新 rangeadd()の後に使ったらだめ 単位元が0以外の時だけ使う
    i+=(1<<18)-1;
    segdata[i]=x;
    while(i>0){
        i=(i-1)/2;
        segdata[i]=calc(segdata[i*2+1],segdata[i*2+2]);
    }
}
void eval(lint k,lint l,lint r){
    if(lazy[k]){
        segdata[k]+=lazy[k];
        if(r-l>1) lazy[2*k+1]+=lazy[k]/2,lazy[2*k+2]+=lazy[k]/2;
        lazy[k]=0;
    }
}
void add(lint a,lint b,lint x,lint k,lint l,lint r){
    eval(k,l,r);
    if(r<=a || b<=l) return;
    if(a<=l && r<=b){
        lazy[k]+=(r-l)*x;
        eval(k,l,r);
    }
    else{
        add(a,b,x,2*k+1,l,(l+r)/2);
        add(a,b,x,2*k+2,(l+r)/2,r);
        segdata[k]=calc(segdata[2*k+1],segdata[2*k+2]);
    }
}
lint seg(lint a,lint b,lint k,lint l,lint r){
    eval(k,l,r);
    if(r<=a || b<=l) return neutral();
    if(a<=l && r<=b) return segdata[k];
    else{
        lint left=seg(a,b,k*2+1,l,(l+r)/2);
        lint right=seg(a,b,k*2+2,(l+r)/2,r);
        return calc(left,right);
    }
}
lint query(lint a,lint b){
    return seg(a,b+1,0,0,1<<18); //a~b(閉区間）の範囲での演算
}
void rangeadd(lint a,lint b,lint x){ //a~b(閉区間)にxを加算
    add(a,b+1,x,0,0,1<<18); 
    return;
}

int main(void){
    lint N,K;
    cin >> N >> K;
    lint L[K],R[K];
    rep(i,K) cin >> L[i] >> R[i];
    seginit();
    rangeadd(0,0,1);
    rep(i,N-1){
        rep(j,K){
            int l=i+L[j],r=i+R[j];
            if(l>=N) continue;
            if(r>=N) r=N-1;
            rangeadd(l,r,query(i,i));
        }
    }
    cout << query(N-1,N-1) << endl;
}