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

#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char *argv[]) {
  const int BIG = 1000000;
  const int CMAX = 25000;
  for (;;) {
    int n;
    cin >> n;
    if (n == 0)
      break;
    vector<int> ps;
    for (int i = 0; i < n; i++) {
      int p;
      cin >> p;
      ps.push_back(p);
    }
    // shop : at most 100
    // change : at most 49900... too much?
    // # of 500 got so far : at most 100
    // value : minimum payment

    vector<vector<int>> dp(CMAX + 1, vector<int>(101, BIG));
    vector<vector<int>> dpnew(CMAX + 1, vector<int>(101, BIG));
    dpnew[0][0] = 0;
    int cmax = 0;
    int kmax = 0;
    for (int i = 0; i < n; i++) {
      int kmax2 = kmax;
      const int ii = i + 1;
      // not buying
      for (int j = 0; j <= cmax; j++) {
        for (int k = max(0, kmax - (n - i)); k <= i; k++) {
          dp[j][k] = dpnew[j][k];
        }
      }
      // buying
      for (int j = 0; j <= cmax; j++) {
        const int p = ps[i] % 1000;
        if (p != 0 && p <= 500) { // got 500!
          const int jj = min(j + 500 - p, CMAX);
          cmax = min(max(cmax, jj), CMAX);
          for (int k = max(0, kmax - (n - i)); k <= kmax; k++) {
            const int kk = k + 1;
            if (dpnew[jj][kk] > dp[j][k] + ps[i]) {
              dpnew[jj][kk] = dp[j][k] + ps[i];
              kmax2 = max(kmax2, kk);
            }
          }
        } else {
          // get 500 if possible!
          const int q = (p == 0 ? 1000 : p) - 500;
          if (j >= q) {
            const int jj = j - q;
            for (int k = max(0, kmax - (n - i)); k <= kmax; k++) {
              const int kk = k + 1;
              if (dpnew[jj][kk] > dp[j][k] + ps[i]) {
                dpnew[jj][kk] = dp[j][k] + ps[i];
                kmax2 = max(kmax2, kk);
              }
            }
          } else { // get change
            const int jj = j + 1000 - p;
            cmax = min(max(cmax, jj), CMAX);
            if (jj < 1000) {
              for (int k = max(0, kmax - (n - i)); k <= kmax; k++) {
                const int kk = k;
                if (dpnew[jj][kk] > dp[j][k] + ps[i]) {
                  dpnew[jj][kk] = dp[j][k] + ps[i];
                  kmax2 = max(kmax2, kk);
                }
              }
            }
          }
        }
      }
      kmax = kmax2;
    }
    for (int k = 100; k >= 0; k--) {
      int p = BIG;
      for (int j = 0; j <= cmax; j++) {
        p = min(p, dpnew[j][k]);
      }
      if (p != BIG) {
        cout << k << " " << p << endl;
        break;
      }
    }
  }
  return 0;
}


Error: TLE

Fixed submission:

#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char *argv[]) {
  const int BIG = 1000000;
  const int CMAX = 50000;
  for (;;) {
    int n;
    cin >> n;
    if (n == 0)
      break;
    vector<int> ps;
    for (int i = 0; i < n; i++) {
      int p;
      cin >> p;
      ps.push_back(p);
    }
    // shop : at most 100
    // change : at most 49900... too much?
    // # of 500 got so far : at most 100
    // value : minimum payment

    vector<vector<int>> dp(CMAX + 1, vector<int>(101, BIG));
    vector<vector<int>> dpnew(CMAX + 1, vector<int>(101, BIG));
    dpnew[0][0] = 0;
    int cmax = 0;
    int kmax = 0;
    for (int i = 0; i < n; i++) {
      int kmax2 = kmax;
      const int ii = i + 1;
      for (int j = 0; j <= cmax; j++) { // not buying
        for (int k = max(0, kmax - (n - i)); k <= i; k++) {
          dp[j][k] = dpnew[j][k];
        }
      }
      // buying
      const int p = ps[i] % 1000;
      if (p != 0 && p <= 500) { // got 500!
        for (int j = 0; j <= cmax; j++) {
          const int jj = min(j + 500 - p, CMAX);
          cmax = min(max(cmax, jj), CMAX);
          for (int k = max(0, kmax - (n - i)); k <= kmax; k++) {
            const int kk = k + 1;
            if (dpnew[jj][kk] > dp[j][k] + ps[i]) {
              dpnew[jj][kk] = dp[j][k] + ps[i];
              kmax2 = max(kmax2, kk);
            }
          }
        }
      } else {
        // get 500 if possible!
        const int q = (p == 0 ? 1000 : p) - 500;
        for (int j = 0; j <= cmax; j++) {
          if (j >= q) {
            const int jj = j - q;
            for (int k = max(0, kmax - (n - i)); k <= kmax; k++) {
              const int kk = k + 1;
              if (dpnew[jj][kk] > dp[j][k] + ps[i]) {
                dpnew[jj][kk] = dp[j][k] + ps[i];
                kmax2 = max(kmax2, kk);
              }
            }
          } else { // get change
            const int jj = j + 1000 - p;
            cmax = min(max(cmax, jj), CMAX);
            if (jj < 1000) {
              for (int k = max(0, kmax - (n - i)); k <= kmax; k++) {
                const int kk = k;
                if (dpnew[jj][kk] > dp[j][k] + ps[i]) {
                  dpnew[jj][kk] = dp[j][k] + ps[i];
                  kmax2 = max(kmax2, kk);
                }
              }
            }
          }
        }
      }
      kmax = kmax2;
    }
    for (int k = 100; k >= 0; k--) {
      int p = BIG;
      for (int j = 0; j <= cmax; j++) {
        p = min(p, dpnew[j][k]);
      }
      if (p != BIG) {
        cout << k << " " << p << endl;
        break;
      }
    }
  }
  return 0;
}