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 Java (OpenJDK 11.0.6) (judge verdict: Accepted)

import java.io.*;
import java.util.*;

import static java.lang.Math.*;

public class Main {
    class Reader {
        BufferedReader in;

        Reader() throws IOException {
            in = new BufferedReader(new InputStreamReader(System.in));
        }

        Reader(String name) throws IOException {
            in = new BufferedReader(new FileReader(name));
        }

        StringTokenizer tokin = new StringTokenizer("");

        String next() throws IOException {
            if (!tokin.hasMoreTokens()) {
                tokin = new StringTokenizer(in.readLine());
            }
            return tokin.nextToken();
        }

        int nextInt() throws IOException {
            return Integer.parseInt(next());
        }

        boolean hasNext() throws IOException {
            if (tokin.hasMoreTokens()) {
                return true;
            } else {
                String s = in.readLine();
                while (s != null && s.length() == 0) {
                    s = in.readLine();
                }
                if (s == null) {
                    return false;
                } else {
                    tokin = new StringTokenizer(s);
                    return true;
                }
            }
        }
    }

    class Writer {
        PrintWriter cout;

        Writer() throws IOException {
            cout = new PrintWriter(System.out);
        }

        Writer(String name) throws IOException {
            cout = new PrintWriter(new FileWriter(name));
        }

        StringBuilder out = new StringBuilder();

        void print(Object a) {
            out.append(a);
        }

        void close() {
            cout.print(out.toString());
            cout.close();
        }
    }

    long mod = 998244353;

    class SegmentTree {
        long a[];
        long t[];

        SegmentTree(int n) {
            int k2 = 1;
            while (k2 < n)
                k2 *= 2;
            k2 *= 2;
            a = new long[k2];
            t = new long[k2];
            t[k2 / 2 - 1] = 1;
        }

        void update(int v, int tl, int tr, int l, int r, long add) {
            if (l > r)
                return;
            if (l == tl && tr == r) {
                t[v] = (t[v] + add) % mod;
            } else {
                int tm = (tl + tr) / 2;
                update(v * 2 + 1, tl, tm, l, min(r, tm), add);
                update(v * 2 + 2, tm + 1, tr, max(l, tm + 1), r, add);
            }
        }

        void update(int l, int r, long add) {
            update(0, 0, a.length / 2 - 1, l, r, add);
        }

        long get(int v, int tl, int tr, int pos) {
            if (tl == tr) {
                return t[v];
            }
            int tm = (tl + tr) / 2;
            if (pos <= tm) {
                return (t[v] + get(v * 2 + 1, tl, tm, pos)) % mod;
            } else {
                return (t[v] + get(v * 2 + 2, tm + 1, tr, pos)) % mod;
            }
        }

        long get(int n) {
            return get(0, 0, a.length / 2 - 1, n);
        }
    }


    void run() throws Exception {
        Reader in = new Reader();
        Writer out = new Writer();
        int n = in.nextInt();
        int k = in.nextInt();
        SegmentTree t = new SegmentTree(n);
        int bounds[][] = new int[k][2];
        for (int i = 0; i < k; i++) {
            bounds[i][0] = in.nextInt();
            bounds[i][1] = in.nextInt();
        }
        for (int i = 0; i < n; i++) {
            long val = t.get(i);
            for (int j = 0; j < k; j++) {
                if (bounds[j][0] + i < n) {
                    t.update(bounds[j][0] + i, min(bounds[j][1] + i, n - 1), val);
                }
            }
        }
        out.print(t.get(n - 1));
        out.close();
    }

    public static void main(String[] args) throws Exception {
        new Main().run();
    }
}