// template {{{
#![allow(clippy::many_single_char_names)]

#[allow(dead_code)]
mod ngtio {
    use ::std::collections::VecDeque;

    pub struct Buffer {
        buf: VecDeque<String>,
    }

    impl Buffer {
        pub fn new() -> Self {
            Self {
                buf: VecDeque::new(),
            }
        }

        fn load(&mut self) {
            while self.buf.is_empty() {
                let mut s = String::new();
                let length = ::std::io::stdin().read_line(&mut s).unwrap();
                if length == 0 {
                    break;
                }
                self.buf.extend(s.split_whitespace().map(|s| s.to_owned()));
            }
        }

        pub fn string(&mut self) -> String {
            self.load();
            self.buf
                .pop_front()
                .unwrap_or_else(|| panic!("入力が終了したのですが。"))
        }

        pub fn string_char_vec(&mut self) -> Vec<char> {
            let s = self.string();
            s.chars().collect::<Vec<_>>()
        }

        pub fn string_char_vec_trusted_len(&mut self, len: usize) -> Vec<char> {
            let s = self.string();
            let s = s.chars().collect::<Vec<_>>();
            assert_eq!(s.len(), len, "あら、思ったのと長さ違いますね……");
            s
        }

        pub fn char(&mut self) -> char {
            let string = self.string();
            let mut chars = string.chars();
            let res = chars.next().unwrap();
            assert!(
                chars.next().is_none(),
                "char で受け取りたいのも山々なのですが、さては 2 文字以上ありますね？"
            );
            res
        }

        pub fn read<T: ::std::str::FromStr>(&mut self) -> T
        where
            <T as ::std::str::FromStr>::Err: ::std::fmt::Debug,
        {
            self.string()
                .parse::<T>()
                .expect("Failed to parse the input.")
        }

        pub fn read_vec<T: ::std::str::FromStr>(&mut self, len: usize) -> Vec<T>
        where
            <T as ::std::str::FromStr>::Err: ::std::fmt::Debug,
        {
            (0..len).map(|_| self.read::<T>()).collect()
        }
    }

    macro_rules! define_primitive_reader {
        ($($ty:tt,)*) => {
            impl Buffer {
                $(
#[inline]
                    pub fn $ty(&mut self) -> $ty {
                        self.read::<$ty>()
                    }
                )*
            }
        }
    }

    define_primitive_reader! {
        u8, u16, u32, u64, usize,
        i8, i16, i32, i64, isize,
    }

    impl Default for Buffer {
        fn default() -> Self {
            Self::new()
        }
    }
}

#[allow(unused_imports)]
use std::{collections, iter, mem, ops};
// }}}
// segtree {{{
#[allow(dead_code)]
mod segtree {
    use super::type_traits::*;
    use std::{iter, ops};

    #[derive(Debug, Clone, PartialEq)]
    pub struct Segtree<T> {
        pub head: usize,
        pub len: usize,
        pub table: Vec<T>,
    }

    impl<T: Assoc> Segtree<T> {
        pub fn from_slice(src: &[T]) -> Self {
            if src.is_empty() {
                Self {
                    head: 0,
                    len: 0,
                    table: Vec::new(),
                }
            } else {
                let head = src.len() - 1;
                let mut me = Self {
                    head,
                    len: src.len(),
                    table: src[1..].iter().chain(src).cloned().collect::<Vec<_>>(),
                };
                for i in (0..head).rev() {
                    me.update(i);
                }
                me
            }
        }

        pub fn set(&mut self, i: usize, x: T) {
            assert!(i < self.len);
            self.modify(i, |y| y.clone_from(&x));
        }

        pub fn get(&mut self, i: usize) -> &T {
            assert!(i < self.len);
            &self.table[self.head + i]
        }

        pub fn modify(&mut self, mut i: usize, f: impl Fn(&mut T)) {
            assert!(i < self.len);
            i += self.head;
            f(&mut self.table[i]);
            for i in iter::successors(Some((i - 1) / 2), |&x| {
                if x == 0 {
                    None
                } else {
                    Some((x - 1) / 2)
                }
            }) {
                self.update(i);
            }
        }

        pub fn fold(&self, range: impl ops::RangeBounds<usize>) -> Option<T> {
            let (mut start, mut end) = open(self.len, range);
            assert!(start <= end, "変な区間を渡すのをやめませんか？");
            assert!(end <= self.len, "範囲外です！");
            start += self.head;
            end += self.head;

            if start == end {
                None
            } else if start + 1 == end {
                Some(self.table[start].clone())
            } else {
                let mut left = self.table[start].clone();
                start += 1;
                end -= 1;
                let mut right = self.table[end].clone();
                while start != end {
                    if start % 2 == 0 {
                        left.op_from_right(&self.table[start]);
                        start += 1;
                    }
                    if end % 2 == 0 {
                        end -= 1;
                        right.op_from_left(&self.table[end]);
                    }
                    start = (start - 1) / 2;
                    end = (end - 1) / 2;
                }
                Some(T::op(left, right))
            }
        }

        fn update(&mut self, i: usize) {
            let x = T::op(self.table[2 * i + 1].clone(), self.table[2 * i + 2].clone());
            self.table[i] = x;
        }
    }

    fn open(len: usize, range: impl ops::RangeBounds<usize>) -> (usize, usize) {
        use ops::Bound::*;
        (
            match range.start_bound() {
                Unbounded => 0,
                Included(&x) => x,
                Excluded(&x) => x + 1,
            },
            match range.end_bound() {
                Excluded(&x) => x,
                Included(&x) => x + 1,
                Unbounded => len,
            },
        )
    }
}
// }}}
// type_traits {{{
#[allow(dead_code)]
mod type_traits {
    #![warn(missing_docs)]

    use std::{cmp, ops};

    mod primitive {
        use super::{One, Zero};

        macro_rules! int {
            ($($T:ty,)*) => {
                $(
                    impl Zero for $T {
                        fn zero() -> $T {
                            0
                        }
                        fn times(self, n: u64) -> $T {
                            self * n as $T
                        }
                        fn times_assign(&mut self, n: u64) {
                            *self *= n as $T
                        }
                        fn from_u64(n: u64) -> $T {
                            n as $T
                        }
                    }
                    impl One for $T {
                        fn one() -> $T {
                            1
                        }
                    }
                )*
            }
        }

        int! {
            u8, u16, u32, u64, u128, usize,
            i8, i16, i32, i64, i128, isize,
        }
    }

    pub mod wrappers {
        use super::{Assoc, Element, Identity, One, Zero};
        use std::ops;

        #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
        pub struct Add<T>(pub T);
        impl<T> Assoc for Add<T>
        where
            T: ops::Add<Output = T> + Element,
        {
            fn op(self, rhs: Self) -> Self {
                Add(self.0 + rhs.0)
            }
        }
        impl<T> Identity for Add<T>
        where
            T: Zero,
        {
            fn identity() -> Self {
                Add(T::zero())
            }
        }

        #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
        pub struct Mul<T>(pub T);

        impl<T> Assoc for Mul<T>
        where
            T: ops::Mul<Output = T> + Element,
        {
            fn op(self, rhs: Self) -> Self {
                Mul(self.0 * rhs.0)
            }
        }
        impl<T> Identity for Mul<T>
        where
            T: One,
        {
            fn identity() -> Self {
                Mul(T::one())
            }
        }

        #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
        pub struct Affine<T> {
            pub a: T,
            pub b: T,
        }

        impl<T> Assoc for Affine<T>
        where
            T: ops::Add<Output = T> + Element,
            T: ops::Mul<Output = T> + Element,
        {
            fn op(self, rhs: Self) -> Self {
                Self {
                    a: self.a.clone() * rhs.a,
                    b: self.b + self.a * rhs.b,
                }
            }
        }
        impl<T> Identity for Affine<T>
        where
            T: Zero + One,
        {
            fn identity() -> Self {
                Self {
                    a: T::one(),
                    b: T::zero(),
                }
            }
        }

        #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
        pub struct Cat(pub String);

        impl Assoc for Cat {
            fn op(self, rhs: Self) -> Self {
                Cat(self.0.chars().chain(rhs.0.chars()).collect())
            }
        }
        impl Identity for Cat {
            fn identity() -> Self {
                Cat(String::new())
            }
        }
    }

    pub trait Element: Sized + Clone + PartialEq {}
    impl<T: Sized + Clone + PartialEq> Element for T {}

    pub trait Assoc: Element {
        fn op(self, rhs: Self) -> Self;

        fn op_from_left(&mut self, left: &Self) {
            *self = Self::op(left.clone(), self.clone());
        }

        fn op_from_right(&mut self, right: &Self) {
            *self = Self::op(self.clone(), right.clone());
        }
    }

    pub trait Identity: Assoc {
        fn identity() -> Self;
    }

    pub trait Zero: ops::Add<Output = Self> + ops::AddAssign + Element {
        fn zero() -> Self;

        fn is_zero(&self) -> bool
        where
            Self: cmp::PartialEq,
        {
            self == &Self::zero()
        }

        fn times(self, n: u64) -> Self;

        fn times_assign(&mut self, n: u64);

        fn from_u64(x: u64) -> Self;
    }

    pub trait One: ops::Mul<Output = Self> + ops::MulAssign + Element {
        fn one() -> Self;

        fn is_one(&self) -> bool
        where
            Self: cmp::PartialEq,
        {
            self == &Self::one()
        }
    }

    pub trait Ring: Zero + One + ops::Neg + ops::Sub<Output = Self> + ops::SubAssign {}
    impl<T: Zero + One + ops::Neg + ops::Sub<Output = Self> + ops::SubAssign> Ring for T {}

    #[macro_export]
    macro_rules! define_constant {
        ($(#[$attr:meta])? $vis:vis type $wrapper_type:ident: $value_type:ty = $value:expr;) => {
            $(#[$attr])?
            #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
            $vis struct $wrapper_type {}

            impl Constant for $wrapper_type {
                type Output = $value_type;
                const VALUE: Self::Output = $value;
            }
        };
    }

    pub trait Constant: Copy {
        type Output: Copy;

        const VALUE: Self::Output;
    }
}
// }}}
// fp {{{
#[allow(dead_code)]
mod fp {
    #![warn(missing_docs)]
    use crate::type_traits::*;
    pub use aliases::*;
    use std::{cmp, fmt, iter, mem, ops::*};

    mod arith {
        use super::{Fp, Modable, Value};
        use crate::type_traits::*;
        use std::ops::*;

        impl<Mod: Modable> Add for Fp<Mod>
        where
            Mod::Output: Value,
        {
            type Output = Self;

            #[inline]
            fn add(self, rhs: Self) -> Self {
                Self(Self::normalize_from_the_bottom(
                    self.into_inner() + rhs.into_inner(),
                ))
            }
        }

        impl<Mod: Modable> Sub for Fp<Mod>
        where
            Mod::Output: Value,
        {
            type Output = Self;

            #[inline]
            fn sub(self, rhs: Self) -> Self {
                Self(Self::normalize_from_the_top(
                    self.into_inner() - rhs.into_inner(),
                ))
            }
        }

        impl<Mod: Modable> Mul for Fp<Mod>
        where
            Mod::Output: Value,
        {
            type Output = Self;

            #[inline]
            fn mul(self, rhs: Self) -> Self {
                Self::new(self.into_inner() * rhs.into_inner())
            }
        }

        #[allow(clippy::suspicious_arithmetic_impl)]
        impl<Mod: Modable> Div for Fp<Mod>
        where
            Mod::Output: Value,
        {
            type Output = Self;

            #[inline]
            fn div(self, rhs: Self) -> Self {
                self * rhs.inv()
            }
        }

        impl<Mod: Modable> Neg for Fp<Mod>
        where
            Mod::Output: Value,
        {
            type Output = Self;

            #[inline]
            fn neg(self) -> Self {
                if self.into_inner().is_zero() {
                    Self::zero()
                } else {
                    Self(Mod::VALUE - self.into_inner())
                }
            }
        }

        impl<Mod: Modable> Neg for &Fp<Mod>
        where
            Mod::Output: Value,
        {
            type Output = Fp<Mod>;

            #[inline]
            fn neg(self) -> Fp<Mod> {
                if self.into_inner().is_zero() {
                    Fp::zero()
                } else {
                    Fp(Mod::VALUE - self.into_inner())
                }
            }
        }

        macro_rules! forward_assign_biop {
            ($(impl $trait:ident, $fn_assign:ident, $fn:ident)*) => {
                $(
                    impl<Mod: Modable> $trait for Fp<Mod>
                    where
                        Mod::Output: Value
                    {
                        #[inline]
                        fn $fn_assign(&mut self, rhs: Self) {
                            *self = self.$fn(rhs);
                        }
                    }
                )*
            };
        }
        forward_assign_biop! {
            impl AddAssign, add_assign, add
            impl SubAssign, sub_assign, sub
            impl MulAssign, mul_assign, mul
            impl DivAssign, div_assign, div
        }

        macro_rules! forward_ref_binop {
            ($(impl $imp:ident, $method:ident)*) => {
                $(
                    impl<'a, Mod: Modable> $imp<Fp<Mod>> for &'a Fp<Mod>
                    where
                        Mod::Output:Value
                    {
                        type Output = Fp<Mod>;

                        #[inline]
                        fn $method(self, other: Fp<Mod>) -> Self::Output {
                            $imp::$method(*self, other)
                        }
                    }

                    impl<'a, Mod: Modable> $imp<&'a Fp<Mod>> for Fp<Mod>
                    where
                        Mod::Output:Value
                    {
                        type Output = Fp<Mod>;

                        #[inline]
                        fn $method(self, other: &Fp<Mod>) -> Self::Output {
                            $imp::$method(self, *other)
                        }
                    }

                    impl<'a, Mod: Modable> $imp<&'a Fp<Mod>> for &'a Fp<Mod>
                    where
                        Mod::Output:Value
                    {
                        type Output = Fp<Mod>;

                        #[inline]
                        fn $method(self, other: &Fp<Mod>) -> Self::Output {
                            $imp::$method(*self, *other)
                        }
                    }
                )*
            };
        }
        forward_ref_binop! {
            impl Add, add
            impl Sub, sub
            impl Mul, mul
            impl Div, div
        }
    }

    #[macro_export]
    macro_rules! fp_vec {
        () => (
            Vec::<$crate::Fp<_>>::new()
        );
        ($elem:expr; $n:expr) => (
            vec![$crate::Fp::new($elem); $n]
        );
        ($($x:expr),+ $(,)?) => (
            vec![$($crate::Fp::new($x),)+];
        );
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    pub struct Fp<Mod: Modable>(Mod::Output);

    impl<Mod: Modable> Fp<Mod>
    where
        Mod::Output: Value,
    {
        #[inline]
        pub fn new(src: Mod::Output) -> Self {
            Self(Self::normalize(src))
        }

        #[inline]
        pub fn frac(num: Mod::Output, den: Mod::Output) -> Self {
            Self::new(num) / Self::new(den)
        }

        #[inline]
        pub fn into_inner(self) -> Mod::Output {
            self.0
        }

        #[allow(clippy::many_single_char_names)]
        pub fn inv(self) -> Self {
            assert_ne!(
                self.into_inner(),
                Mod::Output::zero(),
                "さては 0 の逆元を取ろうとしていますね？"
            );
            let mut x = self.into_inner();
            let mut y = Mod::VALUE;
            let mut u = Mod::Output::one();
            let mut v = Mod::Output::zero();
            while x != Mod::Output::zero() {
                let q = y / x;
                y -= q * x;
                v -= q * u;
                mem::swap(&mut x, &mut y);
                mem::swap(&mut u, &mut v);
            }
            assert!(
                x == Mod::Output::zero()
                    && y == Mod::Output::one()
                    && (u == Mod::VALUE || u == -Mod::VALUE)
                    && (-Mod::VALUE < v && v < Mod::VALUE)
            );
            Self(Self::normalize_from_the_top(v))
        }

        pub fn pow(mut self, mut p: u64) -> Self {
            let mut ans = Self::one();
            while p != 0 {
                if p % 2 == 1 {
                    ans *= self;
                }
                self *= self;
                p /= 2;
            }
            ans
        }

        #[inline]
        fn normalize(src: Mod::Output) -> Mod::Output {
            Self::normalize_from_the_top(src % Mod::VALUE)
        }

        #[inline]
        fn normalize_from_the_bottom(src: Mod::Output) -> Mod::Output {
            if Mod::VALUE <= src {
                src - Mod::VALUE
            } else {
                src
            }
        }

        #[inline]
        fn normalize_from_the_top(src: Mod::Output) -> Mod::Output {
            if src < Mod::Output::zero() {
                src + Mod::VALUE
            } else {
                src
            }
        }
    }

    impl<Mod: Modable> Zero for Fp<Mod>
    where
        Mod::Output: Value,
    {
        #[inline]
        fn zero() -> Fp<Mod> {
            Fp::new(Mod::Output::zero())
        }
        fn times(self, n: u64) -> Fp<Mod> {
            self * Fp::from_u64(n)
        }
        fn times_assign(&mut self, n: u64) {
            *self *= Fp::from_u64(n)
        }
        fn from_u64(n: u64) -> Fp<Mod> {
            Fp::new(Mod::Output::from_u64(n))
        }
    }

    impl<Mod: Modable> One for Fp<Mod>
    where
        Mod::Output: Value,
    {
        #[inline]
        fn one() -> Fp<Mod> {
            Fp::new(Mod::Output::one())
        }
    }

    impl<Mod: Modable> iter::Sum<Fp<Mod>> for Fp<Mod>
    where
        Mod::Output: Value,
    {
        fn sum<I>(iter: I) -> Self
        where
            I: iter::Iterator<Item = Fp<Mod>>,
        {
            iter.fold(Fp::zero(), Add::add)
        }
    }

    impl<'a, Mod: 'a + Modable> iter::Sum<&'a Fp<Mod>> for Fp<Mod>
    where
        Mod::Output: Value,
    {
        fn sum<I>(iter: I) -> Self
        where
            I: iter::Iterator<Item = &'a Fp<Mod>>,
        {
            iter.fold(Fp::zero(), Add::add)
        }
    }

    impl<Mod: Modable> iter::Product<Fp<Mod>> for Fp<Mod>
    where
        Mod::Output: Value,
    {
        fn product<I>(iter: I) -> Self
        where
            I: iter::Iterator<Item = Fp<Mod>>,
        {
            iter.fold(Self::one(), Mul::mul)
        }
    }

    impl<'a, Mod: 'a + Modable> iter::Product<&'a Fp<Mod>> for Fp<Mod>
    where
        Mod::Output: Value,
    {
        fn product<I>(iter: I) -> Self
        where
            I: iter::Iterator<Item = &'a Fp<Mod>>,
        {
            iter.fold(Self::one(), Mul::mul)
        }
    }

    impl<Mod: Modable> fmt::Display for Fp<Mod>
    where
        Mod::Output: Value,
    {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
            write!(f, "{}", self.0)
        }
    }

    pub trait Modable: Constant + Clone + fmt::Debug + cmp::PartialEq + cmp::Eq {}
    impl<Mod: Constant + Clone + fmt::Debug + cmp::PartialEq + cmp::Eq> Modable for Mod {}

    pub trait Value:
        Sized
        + Clone
        + Copy
        + Ring
        + fmt::Debug
        + fmt::Display
        + cmp::PartialOrd
        + cmp::Ord
        + cmp::Eq
        + Div<Output = Self>
        + Rem<Output = Self>
        + Neg<Output = Self>
        + DivAssign
        + RemAssign
    {
    }

    macro_rules! impl_value {
        ($($type:ty,)*) => { $(impl Value for $type {})* };
    }

    impl_value! { i8, i16, i32, i64, i128, isize, }

    mod aliases {
        use super::Fp;
        use crate::type_traits::Constant;

        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
        pub struct Mod1000000007 {}
        pub type F1000000007 = Fp<Mod1000000007>;
        impl Constant for Mod1000000007 {
            type Output = i64;
            const VALUE: i64 = 1_000_000_007;
        }

        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
        pub struct Mod998244353 {}
        pub type F998244353 = Fp<Mod998244353>;
        impl Constant for Mod998244353 {
            type Output = i64;
            const VALUE: i64 = 998_244_353;
        }
    }
}
// }}}

type Fp = fp::F998244353;

use type_traits::wrappers::Add;
use type_traits::{Assoc, One, Zero};

fn main() {
    let mut buf = ngtio::Buffer::new();
    let n = buf.usize();
    let k = buf.usize();
    let trans = iter::repeat_with(|| (buf.usize(), buf.usize()))
        .take(k)
        .collect::<Vec<_>>();
    let mut seg = segtree::Segtree::from_slice(&vec![Add(Fp::zero()); n]);
    seg.set(0, Add(Fp::one()));
    for i in 1..n {
        for &(short, long) in &trans {
            let l = i.saturating_sub(long);
            let r = i.saturating_sub(short - 1);
            if let Some(x) = seg.fold(l..r) {
                seg.modify(i, |y| y.op_from_right(&x));
            }
        }
    }
    println!("{}", seg.get(n - 1).0);
}


Measured memory_bytes: 6772