Problem p01088 (C++)

Buggy submission (status: 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;
    for (int i = 0; i < n; i++) {
      const int ii = i + 1;
      for (int j = 0; j <= cmax; j++) { // not buying
        for (int k = 0; 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 = 0; k <= i; k++) {
            const int kk = k + 1;
            dpnew[jj][kk] = min(dpnew[jj][kk], dp[j][k] + ps[i]);
          }
        }
      } 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 = 0; k <= i; k++) {
              const int kk = k + 1;
              dpnew[jj][kk] = min(dpnew[jj][kk], dp[j][k] + ps[i]);
            }
          } else { // get change
            const int jj = j + 1000 - p;
            cmax = min(max(cmax, jj), CMAX);
            if (jj < 1000) {
              for (int k = 0; k <= i; k++) {
                const int kk = k;
                dpnew[jj][kk] = min(dpnew[jj][kk], dp[j][k] + ps[i]);
              }
            }
          }
        }
      }
    }
    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;
}


Fixed submission:
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char *argv[]) {
  const int BIG = 1000000;
  const int CMAX = 20000;
  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;
    for (int i = 0; i < n; i++) {
      const int ii = i + 1;
      for (int j = 0; j <= cmax; j++) { // not buying
        for (int k = 0; 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 = 0; k <= i; k++) {
            const int kk = k + 1;
            dpnew[jj][kk] = min(dpnew[jj][kk], dp[j][k] + ps[i]);
          }
        }
      } 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 = 0; k <= i; k++) {
              const int kk = k + 1;
              dpnew[jj][kk] = min(dpnew[jj][kk], dp[j][k] + ps[i]);
            }
          } else { // get change
            const int jj = j + 1000 - p;
            cmax = min(max(cmax, jj), CMAX);
            if (jj < 1000) {
              for (int k = 0; k <= i; k++) {
                const int kk = k;
                dpnew[jj][kk] = min(dpnew[jj][kk], dp[j][k] + ps[i]);
              }
            }
          }
        }
      }
    }
    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;
}