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 Rust (1.42.0) (judge verdict: Accepted)

#![allow(non_snake_case)]

use std::io::{stdin, Read};
use std::str::FromStr;
fn read_option<T: FromStr>() -> Option<T> {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok()
}
fn read<T: FromStr>() -> T {
    let opt = read_option();
    opt.expect("failed to parse token")
}

fn main() {
    let N: usize = read();
    let K: usize = read();
    let mut ranges = vec![];
    for _ in 0..K {
        let l: usize = read();
        let r: usize = read();
        ranges.push((l, r));
    }
    println!("{}", solve1(N, ranges));
}

fn solve1(N: usize, ranges: Vec<(usize, usize)>) -> i64 {
    let MOD = 998244353;
    let mut dp = vec![0; N * 2 + 100];
    let mut pluses: Vec<i64> = vec![0; N * 2 + 100];
    dp[0] = 1;
    let mut plus = 0;
    for i in 0..N {
        plus += pluses[i];
        plus %= MOD;
        dp[i] += plus;
        for &(l, r) in &ranges {
            pluses[i + l] += dp[i];
            pluses[i + l] %= MOD;
            pluses[i + r + 1] -= dp[i];
            pluses[i + r + 1] %= MOD;
        }
    }
    if dp[N - 1] < 0 {
        dp[N - 1] + MOD
    } else {
        dp[N - 1]
    }
}

fn solve2(N: usize, ranges: Vec<(usize, usize)>) -> i64 {
    use std::collections::HashSet;
    let mut S: HashSet<usize> = HashSet::new();
    let MOD = 998244353;
    for (l, r) in ranges {
        for i in l..=r {
            S.insert(i);
        }
    }
    let mut dp = vec![0; N * 2 + 100];
    dp[0] = 1;
    for i in 0..N {
        for &plus in &S {
            dp[i + plus] += dp[i];
            dp[i + plus] %= MOD;
        }
    }
    dp[N - 1]
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn all() {
        for i in 2..10000 {
            assert_eq!(solve1(i, vec![(1, i)]), solve1(i, vec![(1, i)]));
        }
    }
}