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

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)
#define ALL(v) (v).begin(), (v).end()
#define fi first
#define se second
template <typename A, typename B> inline bool chmax(A &a, B b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <typename A, typename B> inline bool chmin(A &a, B b) {
  if (a > b) {
    a = b;
    return 1;
  }
  return 0;
}
typedef long long ll;
typedef pair<int, int> pii;
const ll INF = 1e9 + 100;
const bool debug = 0;
/***************************************/

int N;
int p[100];
int dp[101][25001]; // 500円の枚数, 所持金(100円以下の小銭) = 最小購入金額

int main() {
  while (cin >> N, N) {
    REP(i, N) scanf("%d", p + i);

    fill(dp[0], dp[N + 1], INF);
    dp[0][0] = 0;

    int lim[101] = {};
    for (int i = N - 1; i >= 0; i--) {
      int chg = (1000 - (p[i] % 1000)) % 1000;
      if (chg >= 500)
        chg = 500;
      lim[i] = 500 - chg + lim[i + 1];
    }
    REP(t, N) {
      int chg = 1000 - (p[t] % 1000);
      chg %= 1000;

      for (int i = N; i >= 0; i--) {
        for (int j = min(25000, lim[i] + 1000); j >= 0; j--) {
          if (i) { // 購入して500円玉が増えた場合
            if (chg >= 500) {
              int cur = chg - 500; // 増加
              if (j - cur >= 0 && dp[i - 1][j - cur] != INF)
                chmin(dp[i][j], dp[i - 1][j - cur] + p[t]);
            } else {
              int cur = 500 - chg; // 減少
              if (j + cur <= 25000 && dp[i - 1][j + cur] != INF)
                chmin(dp[i][j], dp[i - 1][j + cur] + p[t]);
            }
          }
          // 購入して500円玉が増えなかった場合
          if (chg < 500 && j - chg >= 0 && dp[i][j - chg] != INF)
            chmin(dp[i][j], dp[i][j - chg] + p[t]);

          // 小銭j円が多すぎて困ることはない
          if (j)
            chmin(dp[i][j - 1], dp[i][j]);
        }
      }
    }
    pii ans;
    for (int i = N; i >= 0; i--) {
      if (dp[i][0] == INF)
        continue;
      ans = pii(i, dp[i][0]);
      break;
    }

    if (debug)
      printf("@ ");
    printf("%d %d\\n", ans.fi, ans.se);
  }
  return 0;
}


Error: TLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)
#define ALL(v) (v).begin(), (v).end()
#define fi first
#define se second
template <typename A, typename B> inline bool chmax(A &a, B b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <typename A, typename B> inline bool chmin(A &a, B b) {
  if (a > b) {
    a = b;
    return 1;
  }
  return 0;
}
typedef long long ll;
typedef pair<int, int> pii;
const ll INF = 1e9 + 100;
const bool debug = 0;
/***************************************/

int N;
int p[100];
int dp[101][25001]; // 500円の枚数, 所持金(100円以下の小銭) = 最小購入金額

int main() {
  while (cin >> N, N) {
    REP(i, N) scanf("%d", p + i);

    fill(dp[0], dp[N + 1], INF);
    dp[0][0] = 0;

    REP(t, N) {
      int chg = 1000 - (p[t] % 1000);
      chg %= 1000;

      for (int i = N; i >= 0; i--) {
        for (int j = 25000; j >= 0; j--) {
          if (i) { // 購入して500円玉が増えた場合
            if (chg >= 500) {
              int cur = chg - 500; // 増加
              if (j - cur >= 0 && dp[i - 1][j - cur] != INF)
                chmin(dp[i][j], dp[i - 1][j - cur] + p[t]);
            } else {
              int cur = 500 - chg; // 減少
              if (j + cur <= 25000 && dp[i - 1][j + cur] != INF)
                chmin(dp[i][j], dp[i - 1][j + cur] + p[t]);
            }
          }
          // 購入して500円玉が増えなかった場合
          if (chg < 500 && j - chg >= 0 && dp[i][j - chg] != INF)
            chmin(dp[i][j], dp[i][j - chg] + p[t]);

          // 小銭j円が多すぎて困ることはないので
          if (j)
            chmin(dp[i][j - 1], dp[i][j]);
        }
      }
    }
    pii ans;
    for (int i = N; i >= 0; i--) {
      if (dp[i][0] == INF)
        continue;
      ans = pii(i, dp[i][0]);
      break;
    }

    if (debug)
      printf("@ ");
    printf("%d %d\\n", ans.fi, ans.se);
  }
  return 0;
}