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# (.NET Core 3.1.201) (judge verdict: Wrong Answer)

using static System.Math;
using static System.Console;
using System.Collections.Generic;
using System.Linq;
using System;

class Program
{
    #region Reader
    static string ReadStr => Console.ReadLine();
    static string[] ReadStrs => Console.ReadLine().Split(' ');
    static int ReadInt => Convert.ToInt32(Console.ReadLine().Trim());
    static int[] ReadInts => Console.ReadLine().Trim().Split(' ').Select(s => Convert.ToInt32(s)).ToArray();
    static long ReadLong => Convert.ToInt64(Console.ReadLine().Trim());
    static long[] ReadLongs => Console.ReadLine().Trim().Split(' ').Select(s => Convert.ToInt64(s)).ToArray();
    #endregion
    #region Method
    const int mod = 1000000007;
    public static int Mod(int a, int mod) { return a % mod >= 0 ? a % mod : a % mod + mod; }
    public static long Mod(long a, long mod = mod) { return a % mod >= 0 ? a % mod : a % mod + mod; }
    #endregion





    /// <summary>
    /// 最大公約数
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <returns></returns>
    public static long Gcd(long a, long b)
    {
        if (a < b)
            // 引数を入替えて自分を呼び出す
            return Gcd(b, a);
        while (b != 0)
        {
            var remainder = a % b;
            a = b;
            b = remainder;
        }
        return a;
    }



    public static Dictionary<int, int> PrimeFactors(int n)
    {
        int i = 2;
        int tmp = n;
        Dictionary<int, int> d = new Dictionary<int, int>();

        while (i * i <= n) //※1
        {
            if (tmp % i == 0)
            {
                tmp /= i;
                if (d.ContainsKey(i)) d[i]++;
                else d.Add(i, 1);
            }
            else
            {
                i++;
            }
        }
        if (tmp != 1)
        {
            if (d.ContainsKey(tmp)) d[tmp]++;
            else d.Add(tmp, 1);
        }
        return d;
    }


    #region Mod
    public static long GetInv(long a, long mod = 1000000007)
    {
        return PowerMod(a, mod - 2, mod);
    }
    public static long Combination(long a, long b, long mod = 1000000007)
    {
        if (b < 0 || b > a) return 0;
        if (b > a / 2) b = a - b;
        long numerator = Factorial(a, mod);
        long denominator = (Factorial(b, mod) * Factorial(a - b, mod)) % mod;

        return (numerator * GetInv(denominator, mod)) % mod;
    }
    public static long Factorial(long n, long mod = 1000000007)
    {
        if (n == 0) return 1;
        if (n == 1) return 1;
        long ans = n;
        for (int i = 2; i < n; i++)
        {
            ans = (ans * i) % mod;
        }

        return ans;
    }
    private static long PowerMod(long a, long n, long mod = 1000000007)
    {
        if (n == 0) return 1;
        if (n == 1) return a;

        long p = PowerMod(a, n / 2, mod);
        if (n % 2 == 1) return ((p * p) % mod * a) % mod;
        else return (p * p) % mod;
    }
    #endregion


    static List<long> Divisor(long N)
    {
        List<long> ans = new List<long>();
        int max = (int)Math.Sqrt(N);
        for (int i = 1; i < max; i++)
        {
            if (N % i == 0)
            {
                ans.Add(i);
                ans.Add(N / i);
            }
        }

        if (N % max == 0)
        {
            if (N / max == max) ans.Add(max);
            else
            {
                ans.Add(max);
                ans.Add(N / max);
            }
        }
        return ans;
    }


    #region SegmentTree_Lazy

    /// <summary>
    /// 行う演算は結合法則を満たす必要あり
    /// </summary>
    public class SegmentTree<T> where T : IComparable
    {
        /// <summary>
        /// 完全二分木
        /// </summary>
        protected T[] Data { get; }

        /// <summary>
        /// 完全二分木に含まれる葉の数
        /// </summary>
        protected int LeavesCount { get; }

        /// <summary>
        /// 数列(問題などで与えられる)の要素数
        /// </summary>
        public int Count { get; }

        /// <summary>
        /// 葉のうち使われなかったもの、そしてQueryで引数として取得した範囲がDataのインデックスの外である場合に使う
        /// </summary>
        public T Default { get; }

        protected T[] lazy;


        public SegmentTree(T[] data, T def)
        {

            //初期値の設定
            Count = data.Length;
            Default = def;
            LeavesCount = (int)Pow(2, Ceiling(Log(data.Length, 2)));
            Data = new T[LeavesCount * 2 - 1];
            lazy = new T[LeavesCount * 2 - 1];
            //

            //完全二分木の全要素を初期化
            for (int i = 0; i < Data.Length; i++)
            {
                Data[i] = def;
                lazy[i] = def;
            }

            //dataを用いて必要な要素をすべて埋める
            for (int i = 0; i < data.Length; i++)
            {
                this[i] = data[i];
            }

        }

        public T this[int index]
        {
            get
            {
                return Query(index, index + 1);
            }
            set
            {
                Update(index, index + 1, value);
            }
        }

        public void Update(int a, int b, T newValue)
        {
            Update_sub(a, b, 0, LeavesCount, 0, newValue);
        }

        protected virtual void Update_sub(int a, int b, int l, int r, int current, T newValue)
        {
            Eval(current);
            if (a <= l && r <= b)
            {
                lazy[current] = newValue;
                Eval(current);
            }
            else if (a < r && l < b)
            {
                var children = GetChildIndexes(current);

                Update_sub(a, b, l, (l + r) / 2, children.l, newValue);
                Update_sub(a, b, (l + r) / 2, r, children.r, newValue);
                Data[current] = Select(Data[children.l], Data[children.r]);
            }
        }


        /// <summary>
        /// 唯一の親のインデックスを返す
        /// </summary>
        /// <param name="childIndex"></param>
        /// <returns></returns>
        private int GetParentIndex(int childIndex)
        {
            return (childIndex - 1) / 2;
        }

        /// <summary>
        /// 二つの子のインデックスを返す
        /// </summary>
        /// <param name="parentIndex"></param>
        /// <returns>小さいほうはl、大きいほうはr</returns>
        protected (int l, int r) GetChildIndexes(int parentIndex)
        {
            return (2 * parentIndex + 1, 2 * parentIndex + 2);
        }

        /// <summary>
        /// 親の値を二つの子から決定する
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        private T DecideNewElementFromTwoChildren(int index)
        {
            var children = GetChildIndexes(index);

            return Select(Data[children.l], Data[children.r]);
        }



        /// <summary>
        /// [a,b)の範囲で回答を探す
        /// </summary>
        /// <param name="a"></param>
        /// <param name="halfOpen_b"></param>
        /// <returns></returns>
        public T Query(int a, int halfOpen_b)
        {
            return _Query(a, halfOpen_b, 0, LeavesCount, 0);
        }

        private T _Query(int a, int b, int l, int r, int current)
        {
            Eval(current);

            //Φ
            if (r <= a || b <= l)
            {
                return Default;
            }
            //部分集合
            else if (a <= l && r <= b)
            {
                return Data[current];
            }
            //一部
            else
            {

                //(1) 範囲[l,r)を分割し、子lの回答と子rの回答を取得
                //(2) 二つの回答を比べて、適切(Selectメソッド)な方を返す


                //(1)
                var children = GetChildIndexes(current);
                T t1 = _Query(a, b, l, (l + r) / 2, children.l);
                T t2 = _Query(a, b, (l + r) / 2, r, children.r);

                //(2)
                return Select(t1, t2);
            }

        }

        /// <summary>
        /// 配列のk番と、その葉をlazyの値に更新
        /// (もしlazyがDefaultなら何もしない)
        /// </summary>
        /// <param name="k"></param>
        public virtual void Eval(int k)
        {
            //kがDefaultの時は、伝搬も自身の更新もしない
            if (lazy[k].Equals(Default))
            {
                return;
            }


            //kが葉でないなら伝搬
            if (k < LeavesCount - 1)
            {
                var children = GetChildIndexes(k);

                lazy[children.l] = lazy[k];
                lazy[children.r] = lazy[k];
            }

            //自信を更新
            Data[k] = lazy[k];


            lazy[k] = Default;
        }





        /// <summary>
        /// カスタマイズするところ。二つの子の値から、親の値を決定する方法を定める。
        /// </summary>
        /// <param name="t1">子の値1</param>
        /// <param name="t2">子の値2</param>
        /// <returns></returns>
        protected T Select(T t1, T t2)
        {
            return t1.CompareTo(t2) < 0 ? t1 : t2;
        }

    }

    /// <summary>
    /// 区間足し算
    /// </summary>
    public class SegmentTreeLong : SegmentTree<long>
    {
        public SegmentTreeLong(long[] data, long def) : base(data, def)
        {
        }

        protected override void Update_sub(int a, int b, int l, int r, int current, long newValue)
        {
            Eval(current);
            if (a <= l && r <= b)
            {
                if (lazy[current] == Default)
                {
                    lazy[current] = newValue;
                }
                else
                {
                    lazy[current] += newValue;
                }
                Eval(current);
            }
            else if (a < r && l < b)
            {
                var children = GetChildIndexes(current);

                Update_sub(a, b, l, (l + r) / 2, children.l, newValue);
                Update_sub(a, b, (l + r) / 2, r, children.r, newValue);
                Data[current] = Select(Data[children.l], Data[children.r]);
            }
        }

        /// <summary>
        /// 配列のk番と、その葉をlazyの値に更新
        /// (もしlazyがDefaultなら何もしない)
        /// </summary>
        /// <param name="k"></param>
        public override void Eval(int k)
        {
            //kがDefaultの時は、伝搬も自身の更新もしない
            if (lazy[k] == Default)
            {
                return;
            }


            //kが葉でないなら伝搬
            if (k < LeavesCount - 1)
            {
                var children = GetChildIndexes(k);

                if (lazy[children.l] == Default)
                {
                    lazy[children.l] = lazy[k];
                }
                else
                {
                    lazy[children.l] += lazy[k];
                }

                if (lazy[children.r] == Default)
                {
                    lazy[children.r] = lazy[k];
                }
                else
                {
                    lazy[children.r] += lazy[k];
                }

            }

            //自信を更新
            if (Data[k] == Default)
            {
                Data[k] = lazy[k];
            }
            else
            {
                Data[k] += lazy[k];
            }



            lazy[k] = Default;
        }
    }

    #endregion



    static void Main()
    {
        int[] NK = ReadInts;
        int N = NK[0];
        int K = NK[1];


        SegmentTreeLong tree = new SegmentTreeLong(new long[N], 100000);
        tree.Update(0, 1, 1);


        List<int[]> leeps = new List<int[]>();

        for (int i = 0; i < K; i++)
        {
            var s = ReadInts;

            leeps.Add(s);
        }

        for (int i = 0; i < N; i++)
        {
            foreach (var item in leeps)
            {
                tree.Update(item[0], item[1] + 1, tree.Query(i,i+1));
                long n = tree.Query(i, i + 1);
            }
        }
        

        WriteLine(tree.Query(N-1,N));
    }
}