Problem p02549 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < n; i++)
using ll = long long;

const int mod = 998244353;

ll dp[200010], cu[200010];
int l[10], r[10];

int main() {
  int n, k;
  cin >> n >> k;
  rep(i, k) { cin >> l[i] >> r[i]; }
  dp[1] = 1;
  dp[2] = -1;
  for (int i = 1; i <= n; i++) {
    dp[i] += dp[i - 1];
    dp[i] %= mod;
    rep(j, k) {
      if (i + l[j] <= n) {
        dp[i + l[j]] += dp[i];
        dp[i + l[j]] %= mod;
      }
      if (i + r[j] + 1 <= n) {
        dp[i + r[j] + 1] -= dp[i];
        dp[i + r[j] + 1] %= mod;
        if (dp[i + r[j] + 1] < 0)
          dp[i + r[j] + 1] += mod;
      }
    }
  }
  cout << dp[n] << endl;
}


Error: TLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < n; i++)
#define repr(i, n) for (int i = n - 1; i >= 0; i--)
#define ALL(x) x.begin(), x.end()
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using vi = vector<int>;
using vvi = vector<vi>;
using vll = vector<ll>;
using vvl = vector<vll>;
const int mod = 998244353;
const int INF = 2e9;
const int MAX = 1e6;

struct unionfind {
  vector<int> parent; // 各要素の親のindex(根の場合は-1)
  vector<int> diff_weight; // 各要素の親要素との重さの差分(根の場合は0)
  unionfind(int n) {
    parent.resize(n, -1);
    diff_weight.resize(n, 0);
  }
  int root(int x) { // 要素xの属する集合の根のindex(要素xが根の場合はx)
    if (parent[x] < 0)
      return x;
    int r = root(parent[x]);
    diff_weight[x] += diff_weight[parent[x]];
    return parent[x] = r;
  }
  int weight(int x) { // 要素xとその親要素との重さの差分
    root(x);
    return diff_weight[x];
  }
  void merge(int x, int y) { // 要素xとyを共通の集合に結合
    x = root(x), y = root(y);
    if (x == y)
      return;
    if (parent[x] > parent[y]) {
      swap(x, y);
    }
    parent[x] += parent[y];
    parent[y] = x;
  }
  void merge(int x, int y, int w) { // 要素xとyを共通の集合に結合
    w += weight(x), w -= weight(y);
    x = root(x), y = root(y);
    if (x == y)
      return;
    if (parent[x] > parent[y]) {
      swap(x, y);
      w *= -1;
    }
    parent[x] += parent[y];
    parent[y] = x;
    diff_weight[y] = w;
  }
  bool common(int x, int y) { // 要素xとyが共通の集合に属するか
    return root(x) == root(y);
  }
  int size(int x) { // 要素xの属する集合の大きさ
    return -parent[root(x)];
  }
  int diff(int x, int y) { // 要素xとyの重さの差分
    return weight(y) - weight(x);
  }
};
struct edge {
  int from, to, cost;
};
struct graph {
  int n;
  vector<vector<edge>> G;
  vector<bool> visited;
  vector<int> indeg;
  graph(int _n) {
    n = _n;
    G.resize(n);
    visited.resize(n, false);
    indeg.resize(n, 0);
  }
  void add_edge(int from, int to, int cost) {
    G[from].push_back({from, to, cost});
    indeg[to]++;
  }
  void dfs(int s) {
    visited[s] = true;
    for (edge e : G[s]) {
      if (not visited[e.to])
        continue;
      dfs(e.to);
    }
  }
  void dfs(int s, int i, int _n) { // 深さ制限探索
    visited[s] = true;
    if (i == _n)
      return;
    for (edge e : G[s]) {
      if (visited[e.to])
        continue;
      dfs(e.to, i + 1, _n);
    }
  }
  void dfs(int cur, int prev, bool &closed) { // 閉路の検出
    visited[cur] = true;
    for (edge e : G[cur]) {
      if (not visited[e.to]) {
        dfs(e.to, cur, closed);
      } else if (e.to != prev) {
        closed = true;
      }
    }
  }
  void bfs(int s) {
    queue<int> q;
    q.push(s);
    visited[s] = true;
    while (not q.empty()) {
      int cur = q.front();
      for (edge e : G[cur]) {
        if (not visited[e.to])
          continue;
        q.push(e.to);
        visited[e.to] = true;
      }
    }
  }
  void dijkstra(int s, vector<int> &dist) {
    using pii = pair<int, int>;
    dist.resize(n, INF);
    dist[s] = 0;
    priority_queue<pii, vector<pii>, greater<pii>> pq;
    pq.push({dist[s], s});
    while (not pq.empty()) {
      int cur = pq.top().second;
      pq.pop();
      for (edge e : G[cur]) {
        if (dist[e.to] > dist[cur] + e.cost) {
          dist[e.to] = dist[cur] + e.cost;
          pq.push({dist[e.to], e.to});
        }
      }
    }
  }
  void bellman_ford(int s, vector<int> &dist, bool &negative) {
    fill(visited.begin(), visited.end(), false);
    dfs(s);
    dist.resize(n, INF);
    dist[s] = 0;
    for (int i = 0; i < n; i++) {
      for (int u = 0; u < n; u++) {
        for (edge e : G[u]) {
          if (not visited[e.to])
            continue;
          if (dist[e.to] > dist[u] + e.cost) {
            dist[e.to] = dist[u] + e.cost;
            if (i == n - 1) {
              negative = true;
              return;
            }
          }
        }
      }
    }
  }
  void warshall_floyd(vector<vector<int>> &dist, bool &negative) {
    dist.resize(n, vector<int>(n, INF));
    for (int i = 0; i < n; i++) {
      for (edge e : G[i]) {
        dist[i][e.to] = e.cost;
      }
      dist[i][i] = 0;
    }
    for (int k = 0; k < n; k++) {
      for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
          if (dist[i][k] == INF or dist[k][j] == INF)
            continue;
          if (dist[i][j] > dist[i][k] + dist[k][j]) {
            dist[i][j] = dist[i][k] + dist[k][j];
          }
          if (i == j and dist[i][j] < 0) {
            negative = true;
            return;
          }
        }
      }
    }
  }
  static bool comp(const edge &e1, const edge &e2) { return e1.cost < e2.cost; }
  void kruskal(vector<edge> &edges, int &sum) {
    unionfind mst(n);
    sort(edges.begin(), edges.end(), comp);
    int m = edges.size();
    sum = 0;
    for (int i = 0; i < m; i++) {
      edge e = edges[i];
      if (not mst.common(e.from, e.to)) {
        mst.merge(e.from, e.to);
        sum += e.cost;
      }
    }
  }
  void topological(vector<int> &t) {
    queue<int> q;
    for (int i = 0; i < n; i++) {
      if (indeg[i] == 0) {
        q.push(i);
      }
    }
    while (not q.empty()) {
      int cur = q.front();
      q.pop();
      t.push_back(cur);
      for (edge e : G[cur]) {
        indeg[e.to]--;
        if (indeg[e.to] == 0) {
          q.push(e.to);
        }
      }
    }
  }
};
template <typename T> struct cusum {
  int n;
  vector<T> s;
  cusum(vector<T> &a) {
    n = a.size();
    s.resize(n + 1);
    s[0] = 0;
    for (int i = 1; i <= n; i++) {
      s[i] = s[i - 1] + a[i - 1];
    }
  }
  T sum(int a, int b) { // 半開区間[a,b)の和(0-indexed)
    return s[b] - s[a];
  }
};
template <typename T> struct BIT {
  int MAX;
  vector<T> bit;
  BIT(int n) {
    MAX = n;
    bit.resize(MAX + 1, 0);
  }
  void add(int i, int x) { // i番目(1-indexed)に値xを追加
    while (i <= MAX) {
      bit[i] += x;
      i += i & -i;
    }
  }
  T sum(int i) { // 閉区間[1,i]の和
    T s = 0;
    while (i > 0) {
      s += bit[i];
      i -= i & -i;
    }
    return s;
  }
  T rsq(int a, int b) { // 閉区間[a,b]の和
    return sum(b) - sum(a - 1);
  }
};
template <typename T> bool is_prime(T x) { // 素数判定
  if (x < 2)
    return false;
  for (T i = 2; i * i <= x; i++) {
    if (x % i == 0)
      return false;
  }
  return true;
}
template <typename T> void prime_fact(T x, vector<T> &factor) { // 素因数分解
  for (T i = 2; i * i <= x; i++) {
    while (x % i == 0) {
      factor.push_back(i);
      x /= i;
    }
  }
  if (x != 1) {
    factor.push_back(x);
  }
}
struct erat {
  int MAX;
  vector<int> seive;
  erat(int n) { // エラトステネスのふるい
    MAX = n;
    seive.resize(MAX + 1);
    for (int i = 0; i <= MAX; i++) {
      seive[i] = i;
    }
    for (int i = 2; i <= MAX; i++) {
      if (seive[i] == i) { // seive[i]はiの最大の素因数
        for (int j = i + i; j <= MAX; j += i) {
          seive[j] = i;
        }
      }
    }
  }
  void fact(int x, vector<int> &factor) { // 高速素因数分解
    if (x < 2)
      return;
    while (x > 1 and x % seive[x] == 0) {
      factor.push_back(seive[x]);
      x /= seive[x];
    }
    reverse(factor.begin(), factor.end());
  }
  bool is_prime(int x) { // 素数判定
    if (x >= 2 and seive[x] == x)
      return true;
    return false;
  }
};
template <typename T>
T gcd(T a, T b) { // 整数aとbの最大公約数（ユークリッドの互除法）
  if (b == 0)
    return a;
  return gcd(b, a % b);
}
template <typename T> T gcd(vector<T> &a) { //  3つ以上の整数の最大公約数
  int n = (int)a.size();
  T r;
  for (int i = 0; i < n; i++) {
    if (i == 0)
      r = a[i];
    r = gcd(r, a[i]);
  }
  return r;
}
template <typename T> T lcm(T a, T b) { // 整数aとbの最小公倍数
  return a / gcd(a, b) * b;
}
template <typename T> T lcm(vector<T> &a) { // 3つ以上の整数の最小公倍数
  int n = (int)a.size();
  T r = 1;
  for (int i = 0; i < n; i++) {
    r = lcm(r, a[i]);
  }
  return r;
}
template <typename T> T digit_sum(T n) { // 整数nの格桁の和
  T sum = 0;
  while (n > 0) {
    sum += n % 10;
    n /= 10;
  }
  return sum;
}
template <typename T> T digit_sum(string s) { // 整数nの格桁の和
  int n = (int)s.size();
  T sum = 0;
  for (int i = 0; i < n; i++) {
    sum += s[i] - '0';
  }
  return sum;
}
int eular(int n) { // nと互いに素であるn以下の自然数の個数
  int p = n;
  for (int i = 2; i * i <= n; i++) {
    if (n % i == 0) {
      p -= p / i;
      while (n % i == 0)
        n /= i;
    }
  }
  if (n > 1)
    p -= p / n;
  return p;
}
template <typename T> bool is_triangle(T a, T b, T c) { // 三角形の成立条件
  if (a + b > c && b + c > a && c + a > b)
    return true;
  else
    return false;
}
template <typename T> struct combination {
  int MAX;
  vector<T> f;
  vector<vector<T>> dp;
  combination(int _n) {
    MAX = _n;
    f.resize(MAX + 1, 0);
    for (int i = 0; i <= MAX; i++) {
      if (i == 0)
        f[i] = 1;
      else
        f[i] = i * f[i - 1] % mod;
    }
    dp.resize(MAX + 1, vector<T>(MAX + 1, 0));
  }
  T power(int m, int n) { // m^n
    if (n == 0)
      return 1;
    if (n % 2 == 1)
      return m * power(m, n - 1) % mod;
    T r = power(m, n / 2);
    return r * r % mod;
  }
  T inv(int a, int b) { // a / b % mod
    return a * power(b, mod - 2) % mod;
  }
  T fact(int n) { // n!
    return f[n];
  }
  T perm(int n, int r) { // nPr
    if (n < r)
      return 0;
    return inv(fact(n), fact(n - r));
  }
  T comb(int n, int r) { // nCr
    if (n < r)
      return 0;
    return inv(perm(n, r), fact(r));
  }
  T pie(int n, int k) { // 包除原理
    T s = 0;
    for (int i = 0; i < k; i++) {
      s += power(-1, i) * comb(k, i) * power(k - i, n);
      s %= mod;
      if (s < 0)
        s += mod;
    }
    return s;
  }
  T part(int n, int k) { // 分割数
    if (n < 0)
      return 0;
    if (n == 0 || k == 1)
      return dp[n][k] = 1;
    if (dp[n][k] != 0)
      return dp[n][k];
    return dp[n][k] = (part(n, k - 1) + part(n - k, k)) % mod;
  }
  T stir(int n, int k) { // スターリング数
    if (n < k || (n > 0 && k == 0))
      return 0;
    if (n == k || k == 1)
      return dp[n][k] = 1;
    if (dp[n][k] != 0)
      return dp[n][k];
    return dp[n][k] = (stir(n - 1, k - 1) + k * stir(n - 1, k)) % mod;
  }
  T bell(int n, int k) { // ベル数
    T s = 0;
    for (int i = 0; i <= k; i++) {
      s += stir(n, i);
      s %= mod;
    }
    return s;
  }
};

vector<int> s;
vector<ll> dp(200001);

ll rec(int i) {
  if (i < 1)
    return 0;
  if (dp[i] != 0)
    return dp[i];
  if (i == 1)
    return dp[i] = 1;
  ll r = 0;
  rep(x, (int)s.size()) {
    r += rec(i - s[x]);
    r %= mod;
  }
  return dp[i] = r;
}

int main() {
  int n, k;
  cin >> n >> k;
  rep(i, k) {
    int l, r;
    cin >> l >> r;
    for (int j = l; j <= r; j++) {
      s.push_back(j);
    }
  }
  sort(ALL(s));
  for (int i = 1; i <= n; i++) {
    if (i == 1)
      dp[i] = 1;
    rep(x, (int)s.size()) {
      if (i + s[x] <= n) {
        dp[i + s[x]] += dp[i];
        dp[i + s[x]] %= mod;
      } else {
        break;
      }
    }
  }
  // cout << rec(n) << endl;
  cout << dp[n] << endl;
}