#include <bits/stdc++.h>
using namespace std;
#define M 998244353
long long tree[5000050],dp[3000005],lazy[5000050];
void build(int node, int start, int end)
{
    if(start == end)
    {
        // Leaf node will have a single element
        tree[node] = dp[start];
    }
    else
    {
        int mid = (start + end) / 2;
        // Recurse on the left child
        build(2*node, start, mid);
        // Recurse on the right child
        build(2*node+1, mid+1, end);
        // Internal node will have the sum of both of its children
        tree[node] = (tree[2*node] + tree[2*node+1])%M;
    }
}
void updateRange(int node, int start, int end, int l, int r, int val)
{
    if(lazy[node] != 0)
    { 
        // This node needs to be updated
        tree[node] += (end - start + 1) * lazy[node];    // Update it
        if(start != end)
        {
            lazy[node*2] += lazy[node];    
            lazy[node*2]%=M;              // Mark child as lazy
            lazy[node*2+1] += lazy[node];    
            lazy[node*2+1]%=M;            // Mark child as lazy
        }
        lazy[node] = 0;                                  // Reset it
    }
    if(start > end or start > r or end < l)              // Current segment is not within range [l, r]
        return;
    if(start >= l and end <= r)
    {
        // Segment is fully within range
        tree[node] += ((end - start + 1) * val)%M;
        tree[node]%=M;
        if(start != end)
        {
            // Not leaf node
            lazy[node*2] += val;
            lazy[node*2]%=M;
            lazy[node*2+1] += val;
            lazy[node*2+1]%=M;
        }
        return;
    }
    int mid = (start + end) / 2;
    updateRange(node*2, start, mid, l, r, val);        // Updating left child
    updateRange(node*2 + 1, mid + 1, end, l, r, val);   // Updating right child
    tree[node] = (tree[node*2] + tree[node*2+1])%M;        // Updating root with max value 
}

int queryRange(int node, int start, int end, int l, int r)
{
    if(start > end or start > r or end < l)
        return 0;         // Out of range
    if(lazy[node] != 0)
    {
        // This node needs to be updated
        tree[node] += ((end - start + 1) * lazy[node])%M;    tree[node]%=M;        // Update it
        if(start != end)
        {
            lazy[node*2] += lazy[node];
            lazy[node*2]%=M;         // Mark child as lazy
            lazy[node*2+1] += lazy[node]; 
            lazy[node*2+1]%=M;   // Mark child as lazy
        }
        lazy[node] = 0;                 // Reset it
    }
    if(start >= l and end <= r)             // Current segment is totally within range [l, r]
        return tree[node];
    int mid = (start + end) / 2;
    int p1 = queryRange(node*2, start, mid, l, r);         // Query left child
    int p2 = queryRange(node*2 + 1, mid + 1, end, l, r); // Query right child
    return (p1 + p2)%M;
}
int main() {
    // your code goes here
    #ifndef ONLINE_JUDGE
    freopen("input.txt","r",stdin);
    freopen("res.txt","w",stdout);
    #endif
    ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
   	int n,k;
   	cin>>n>>k;
   	int l[k],r[k],li=0;
   	for(int i=0;i<k;i++)
   		cin>>l[i]>>r[i];
   	for(int i=0;i<=n;i++)
   		dp[i]=0;
   	dp[1]=1;
   	build(1,1,n);
   	//cout<<tree[5]<<endl;
   	for(int i=1;i<=n;i++)
   	{
   		dp[i]=queryRange(1,1,n,i,i)%M;
   		//cout<<dp[i]<<endl;
   		for(int j=0;j<k;j++)
   		{
   			if(i+l[j]<=n)	updateRange(1,1,n,i+l[j],min(i+r[j],n),dp[i]%M);
   		}
   	}
   	//for(int i=1;i<n;i++)
   	//	dp[i]+=dp[i-1];
   	cout<<dp[n]%M;
   	return 0;
}

Measured memory_bytes: 13316