Problem p02992 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int ll

#define REP(i, n) for (int i = 0; i < n; ++i)
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))
#if 0
#define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define DBG(fmt, ...)
#endif

const ll LLINF = (1LL << 60);
const int INF = (1LL << 30);
const double DINF = std::numeric_limits<double>::infinity();
const int MOD = 1000000007;
#define MAX_K 110
#define MAX_ROOT_N 60010

ll N, K;
ll dp[MAX_K][MAX_ROOT_N];
ll sum[MAX_K][MAX_ROOT_N];
vector<pair<ll, ll>>
    pat; // N / j を求めたときに、現れるユニークな数と、その回数

// [lb, ub) の範囲で val 以下の要素で最大のもののインデックスを返す
// なければ -1 を返す
// 同じ数が複数ある場合は一番小さいインデックスを返す
static inline ll bin_search4(const vector<pair<ll, ll>> &v, ll lb, ll ub,
                             ll val) {
  lb--;
  ub--;
  while (ub - lb > 1) {
    ll mid = (lb + ub) / 2;
    if (v[mid].first >= val) {
      ub = mid;
    } else {
      lb = mid;
    }
  }
  // この時点で lb + 1 = ub
  if (v[ub].first <= val) {
    return ub;
  }
  if (lb < 0 || v[lb].first > val) {
    return -1;
  }
  return lb;
}

// i まで見ていて、現在の値が pat[j].first のときのパターン数
ll dfs(ll i, ll j) {
  if (i >= K) {
    return 1;
  }

  // assert(i >= 0 && j >= 0);
  // assert(i < MAX_K);
  // assert(j < MAX_ROOT_N);

  ll &ret = dp[i][j];
  if (~ret) {
    return ret;
  }
  ret = 0;

  j = pat[j].first;

  ll next_j = N / j;
  // next_j が、 pat のインデックスでいうとどこにあたるか
  ll next_j_ind = bin_search4(pat, 0, pat.size(), next_j);
  // [1, next_j_ind] の和が答え
  // assert(next_j_ind >= 0);
  assert(next_j_ind < MAX_ROOT_N);

  DBG("i: %lld j: %lld next_j: %lld next_j_ind: %lld\n", i, j, next_j,
      next_j_ind);

  if (~sum[i][next_j_ind]) {
    return sum[i][next_j_ind];
  }
  // ll& sum_ret = sum[i][next_j_ind];
  // if(~sum_ret) { return sum_ret; }
  // sum_ret = 0;

  // sum でもし有効なところまで終わっているなら、そこから続きだけ計算する

  for (int k = 0; k <= next_j_ind; ++k) {
    sum[i][k] = (dfs(i + 1, k) * pat[k].second) % MOD;
    if (k != 0) {
      sum[i][k] += sum[i][k - 1];
      sum[i][k] %= MOD;
    }

    // sum_ret += (dfs(i+1, k) * pat[k].second) % MOD;
    // sum_ret %= MOD;
  }

  ret = sum[i][next_j_ind];
  return ret;
}
ll solve() {
  for (ll j = 1; j <= N; ++j) {
    ll next_j = N / j;
    ll cnt = (N % j) / next_j;
    pat.push_back(make_pair(j, cnt + 1));
    DBG("j: %lld next_j: %lld cnt: %lld\n", j, next_j, cnt + 1);
    j += cnt;
  }

  // printf("pat.size(): %zu\n", pat.size());

  DBG("---\n");

  MINUS(dp);
  MINUS(sum);
  return dfs(0, 0);
}

signed main() {
  cin >> N >> K;

  ll ans = solve();
  printf("%lld\n", ans);

  return 0;
}


Fixed submission:
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int ll

#define REP(i, n) for (int i = 0; i < n; ++i)
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))
#if 0
#define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define DBG(fmt, ...)
#endif

const ll LLINF = (1LL << 60);
const int INF = (1LL << 30);
const double DINF = std::numeric_limits<double>::infinity();
const int MOD = 1000000007;
#define MAX_K 110
#define MAX_ROOT_N 80010

ll N, K;
ll dp[MAX_K][MAX_ROOT_N];
ll sum[MAX_K][MAX_ROOT_N];
vector<pair<ll, ll>>
    pat; // N / j を求めたときに、現れるユニークな数と、その回数

// [lb, ub) の範囲で val 以下の要素で最大のもののインデックスを返す
// なければ -1 を返す
// 同じ数が複数ある場合は一番小さいインデックスを返す
static inline ll bin_search4(const vector<pair<ll, ll>> &v, ll lb, ll ub,
                             ll val) {
  lb--;
  ub--;
  while (ub - lb > 1) {
    ll mid = (lb + ub) / 2;
    if (v[mid].first >= val) {
      ub = mid;
    } else {
      lb = mid;
    }
  }
  // この時点で lb + 1 = ub
  if (v[ub].first <= val) {
    return ub;
  }
  if (lb < 0 || v[lb].first > val) {
    return -1;
  }
  return lb;
}

// i まで見ていて、現在の値が pat[j].first のときのパターン数
ll dfs(ll i, ll j) {
  if (i >= K) {
    return 1;
  }

  // assert(i >= 0 && j >= 0);
  // assert(i < MAX_K);
  // assert(j < MAX_ROOT_N);

  ll &ret = dp[i][j];
  if (~ret) {
    return ret;
  }
  ret = 0;

  j = pat[j].first;

  ll next_j = N / j;
  // next_j が、 pat のインデックスでいうとどこにあたるか
  ll next_j_ind = bin_search4(pat, 0, pat.size(), next_j);
  // [1, next_j_ind] の和が答え
  // assert(next_j_ind >= 0);
  assert(next_j_ind < MAX_ROOT_N);

  DBG("i: %lld j: %lld next_j: %lld next_j_ind: %lld\n", i, j, next_j,
      next_j_ind);

  if (~sum[i][next_j_ind]) {
    return sum[i][next_j_ind];
  }
  // ll& sum_ret = sum[i][next_j_ind];
  // if(~sum_ret) { return sum_ret; }
  // sum_ret = 0;

  // sum でもし有効なところまで終わっているなら、そこから続きだけ計算する

  for (int k = 0; k <= next_j_ind; ++k) {
    sum[i][k] = (dfs(i + 1, k) * pat[k].second) % MOD;
    if (k != 0) {
      sum[i][k] += sum[i][k - 1];
      sum[i][k] %= MOD;
    }

    // sum_ret += (dfs(i+1, k) * pat[k].second) % MOD;
    // sum_ret %= MOD;
  }

  ret = sum[i][next_j_ind];
  return ret;
}
ll solve() {
  for (ll j = 1; j <= N; ++j) {
    ll next_j = N / j;
    ll cnt = (N % j) / next_j;
    pat.push_back(make_pair(j, cnt + 1));
    DBG("j: %lld next_j: %lld cnt: %lld\n", j, next_j, cnt + 1);
    j += cnt;
  }

  // printf("pat.size(): %zu\n", pat.size());

  DBG("---\n");

  MINUS(dp);
  MINUS(sum);
  return dfs(0, 0);
}

signed main() {
  cin >> N >> K;

  ll ans = solve();
  printf("%lld\n", ans);

  return 0;
}