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: Accepted)

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Tracing;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics.X86;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Extensions;
using DSA;
using static System.Math;
using static Extensions.MathExtension;
using static Extensions.ConsoleInputExtension;
using static Extensions.ConsoleOutputExtension;

class Solver
{
    public void Solve()
    {
        // checked
        {
            //Solve Code Here
            ModInt.Mod = 998244353;
            int n = Cin, k = Cin;
            var ranges = new (int, int)[k];
            for (int i = 0; i < k; i++) ranges[i] = (Cin, Cin);
            var patterns = new SegTree<ModInt>(Enumerable.Repeat(new ModInt(0), n).ToArray(), 0, (a, b) => a + b);
            patterns.Update(0, 1);
            for (int i = 1; i < n; i++)
            {
                ModInt sum = 0;
                for (int j = 0; j < k; j++)
                {
                    sum += patterns.Query(
                        Max(i - ranges[j].Item2, 0),
                        Max(i - ranges[j].Item1 + 1, 0));
                }

                patterns.Update(i, sum);
            }

            Coutln(patterns.Get(n - 1));
        }
    }
}

//Other Classes Here

#if !DEBUG
class EntryPoint
{
    static void Main(string[] args)
    {
        new Solver().Solve();
        Flush();
    }
}

#endif

namespace DSA
{
    public class PriorityQueue<T>
    {
        private readonly List<Tuple<int, T>> _list = new List<Tuple<int, T>>();

        public int Count => _list.Count;

        public void Push(T item, int priority)
        {
            _list.Add(Tuple.Create(priority, item));

            int itemIndex = Count - 1, parentIndex;
            while ((parentIndex = GetParentIndex(itemIndex)) != -1 &&
                   priority > _list[parentIndex].Item1)
            {
                Swap(itemIndex, parentIndex);
                itemIndex = parentIndex;
            }
        }

        private int GetParentIndex(int index)
        {
            if (index == 0) return -1;
            return ((index + 1) >> 1) - 1;
        }

        private Tuple<int, int> GetChildrenIndex(int index)
        {
            var item2 = (index + 1) << 1;
            var item1 = item2 - 1;
            return Tuple.Create(item1, item2);
        }

        public T Pop()
        {
            if (Count <= 0) throw new IndexOutOfRangeException();
            var item = _list[0].Item2;
            _list[0] = _list[Count - 1];
            _list.RemoveAt(Count - 1);

            int index = 0;
            Tuple<int, int> childrenIndex = GetChildrenIndex(index);
            while (childrenIndex.Item1 < Count || childrenIndex.Item2 < Count)
            {
                if (childrenIndex.Item2 >= Count || _list[childrenIndex.Item1].Item1 > _list[childrenIndex.Item2].Item1)
                {
                    if (_list[childrenIndex.Item1].Item1 <= _list[index].Item1) return item;

                    Swap(index, childrenIndex.Item1);
                    index = childrenIndex.Item1;
                }
                else
                {
                    if (_list[childrenIndex.Item2].Item1 <= _list[index].Item1) return item;
                    Swap(index, childrenIndex.Item2);
                    index = childrenIndex.Item2;
                }

                childrenIndex = GetChildrenIndex(index);
            }

            return item;
        }

        public T Peek()
        {
            return _list[0].Item2;
        }

        private void Swap(int index1, int index2)
        {
            var tmp = _list[index1];
            _list[index1] = _list[index2];
            _list[index2] = tmp;
        }
    }

    public class UnionFind
    {
        private readonly int[] _array;

        public UnionFind(int size)
        {
            _array = new int[size];
            for (int i = 0; i < size; i++)
            {
                _array[i] = i;
            }
        }

        public int GetRootNode(int n)
        {
            if (_array[n] == n) return n;
            return _array[n] = GetRootNode(_array[n]);
        }

        public void UnionGroup(int a, int b)
        {
            var rootA = GetRootNode(a);
            var rootB = GetRootNode(b);
            if (rootA == rootB) return;
            _array[rootA] = rootB;
        }

        public bool IsSameGroup(int a, int b) => GetRootNode(a) == GetRootNode(b);

        public bool IsRoot(int n) => _array[n] == n;
    }

    public delegate T SegTreeCombiner<T>(T item1, T item2);

    public class SegTree<T>
    {
        private readonly T _defaultItem;
        private readonly SegTreeCombiner<T> _func;
        private T[] List;
        private int size;

        public SegTree(T[] list, T defaultItem, SegTreeCombiner<T> func)
        {
            _defaultItem = defaultItem;
            _func = func;
            size = 1;
            while (size < list.Length) size <<= 1;
            List = new T[2 * size - 1];
            for (int i = 0; i < list.Length; i++) List[i + size - 1] = list[i];
            for (int i = list.Length; i < size; i++) List[i + size - 1] = defaultItem;
            for (int i = size - 1 - 1; i >= 0; i--)
            {
                List[i] = _func(List[2 * i + 1], List[2 * i + 2]);
            }
        }

        public T Get(int index)
        {
            return List[index + size - 1];
        }

        public void Update(int index, T value)
        {
            index += size - 1;
            List[index] = value;
            while (index > 0)
            {
                index = (index - 1) >> 1;
                List[index] = _func(List[2 * index + 1], List[2 * index + 2]);
            }
        }

        public T Query(int a, int b)
        {
            return Query(a, b, 0, 0, size);
        }

        private T Query(int a, int b, int k, int l, int r)
        {
            if (r <= a || b <= l) return _defaultItem;
            if (a <= l && r <= b) return List[k];
            return _func(Query(a, b, k * 2 + 1, l, (l + r) >> 1), Query(a, b, k * 2 + 2, (l + r) >> 1, r));
        }
    }

    public static class BinarySearch
    {
        public delegate bool Terms<T>(T i);

        public static int UpperBound(int initLeft, int initRight, Terms<int> term)
        {
            int left = initLeft - 1, right = initRight;
            while (right - left > 1)
            {
                int mid = (left + right) >> 1;
                if (mid != initLeft - 1 && term(mid)) left = mid;
                else right = mid;
            }

            return left;
        }

        public static long UpperBound(long initLeft, long initRight, Terms<long> term)
        {
            long left = initLeft - 1, right = initRight;
            while (right - left > 1)
            {
                long mid = (left + right) >> 1;
                if (mid != initLeft - 1 && term(mid)) left = mid;
                else right = mid;
            }

            return left;
        }

        public static int LowerBound(int initLeft, int initRight, Terms<int> term)
        {
            int left = initLeft - 1, right = initRight;
            while (right - left > 1)
            {
                int mid = (left + right) >> 1;
                if (mid != initRight && term(mid)) right = mid;
                else left = mid;
            }

            return right;
        }

        public static long LowerBound(long initLeft, long initRight, Terms<long> term)
        {
            long left = initLeft - 1, right = initRight;
            while (right - left > 1)
            {
                long mid = (left + right) >> 1;
                if (term(mid)) right = mid;
                else left = mid;
            }

            return right;
        }
    }
}


struct ModInt
{
    public long Value { get; }
    public static long Mod { get; set; } = 1000000000L + 7;

    public ModInt(long l)
    {
        long value = l % Mod;
        while (value < 0) value += Mod;
        Value = value % Mod;
    }

    public static implicit operator long(ModInt m)
    {
        return m.Value;
    }

    public static implicit operator ModInt(long l)
    {
        return new ModInt(l);
    }

    public static ModInt operator +(ModInt a, ModInt b)
    {
        return new ModInt(a.Value + b.Value);
    }

    public static ModInt operator -(ModInt a, ModInt b)
    {
        return new ModInt(a.Value - b.Value);
    }

    public static ModInt operator *(ModInt a, ModInt b)
    {
        return new ModInt(a.Value * b.Value);
    }

    public static ModInt operator /(ModInt a, ModInt b)
    {
        return new ModInt(a * b.Inverse());
    }

    public override string ToString()
    {
        return Value.ToString();
    }
}

static class ModIntMath
{
    public static ModInt Pow(this ModInt a, ModInt b)
    {
        var pow = b.Value;
        var m = a;
        ModInt ans = new ModInt(1);
        while (pow != 0)
        {
            if ((pow & 1) == 1)
            {
                ans *= m;
            }

            pow >>= 1;
            m *= m;
        }

        return ans;
    }

    public static ModInt Inverse(this ModInt m)
    {
        return m.Pow((ModInt) (ModInt.Mod - 2));
    }
}


namespace Extensions
{
    public class ConsoleInputExtension
    {
        private static readonly ConsoleInputExtension _cin = new ConsoleInputExtension();

        public static ConsoleInputExtension Cin => _cin;

        private static readonly Queue<string> _inputQueue = new Queue<string>();

        private ConsoleInputExtension()
        {
        }

        public static implicit operator string(ConsoleInputExtension _)
        {
            if (_inputQueue.Count == 0)
                Console.ReadLine().Split(' ')
                    .ForEach(val => _inputQueue.Enqueue(val));
            return _inputQueue.Dequeue();
        }

        public static implicit operator int(ConsoleInputExtension _)
        {
            if (_inputQueue.Count == 0)
                Console.ReadLine().Split(' ')
                    .ForEach(val => _inputQueue.Enqueue(val));
            return int.Parse(_inputQueue.Dequeue());
        }

        public static implicit operator long(ConsoleInputExtension _)
        {
            if (_inputQueue.Count == 0)
                Console.ReadLine().Split(' ')
                    .ForEach(val => _inputQueue.Enqueue(val));
            return long.Parse(_inputQueue.Dequeue());
        }

        public static implicit operator float(ConsoleInputExtension _)
        {
            if (_inputQueue.Count == 0)
                Console.ReadLine().Split(' ')
                    .ForEach(val => _inputQueue.Enqueue(val));
            return float.Parse(_inputQueue.Dequeue());
        }

        public static implicit operator double(ConsoleInputExtension _)
        {
            if (_inputQueue.Count == 0)
                Console.ReadLine().Split(' ')
                    .ForEach(val => _inputQueue.Enqueue(val));
            return double.Parse(_inputQueue.Dequeue());
        }
    }

    public static class ConsoleOutputExtension
    {
        private static StringBuilder _builder = new StringBuilder();

        public static void Cout(object o)
        {
            _builder.Append(o);
        }


        public static void CoutF(object o)
        {
            _builder.Append(o);
            Flush();
        }

        public static void Coutln(object o)
        {
            _builder.Append(o);
            _builder.Append('\n');
        }

        public static void Coutln()
        {
            _builder.Append('\n');
        }

        public static void CoutlnF(object o)
        {
            _builder.Append(o);
            _builder.Append('\n');
            Flush();
        }

        public static void Flush()
        {
            Console.Write(_builder.ToString());
            _builder.Clear();
        }
    }

    public static class MathExtension
    {
        //最小公倍数
        public static int LCM(int num1, int num2)
        {
            var gcd = GCD(num1, num2);
            return num1 * (num2 / gcd);
        }

        public static long LCM(long num1, long num2)
        {
            var gcd = GCD(num1, num2);
            return num1 * (num2 / gcd);
        }

        //最大公約数
        public static int GCD(int num1, int num2)
        {
            int a = Math.Max(num1, num2);
            int b = Math.Min(num1, num2);
            if (b == 0) return a;
            int mod;
            while ((mod = a % b) != 0)
            {
                a = b;
                b = mod;
            }

            return b;
        }

        public static long GCD(long num1, long num2)
        {
            long a = Math.Max(num1, num2);
            long b = Math.Min(num1, num2);
            if (b == 0) return a;
            long mod;
            while ((mod = a % b) != 0)
            {
                a = b;
                b = mod;
            }

            return b;
        }
    }

    public static class EnumerableExtension
    {
        public delegate void Function<in T>(T val);

        public static void ForEach<T>(this IEnumerable<T> enumerable, Function<T> function)
        {
            foreach (var x in enumerable)
            {
                function(x);
            }
        }
    }
}