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

#include <bits/stdc++.h>
#define inf 100000000
using namespace std;

// お土産の購入額と1000札のみで購入したときのおつり
typedef struct {
  int v;
  int cha;
} souv;

// DP配列の中身。500円玉の枚数と、購入額
typedef struct {
  int mon;
  int sum;
} table;

bool cmp(table l, table r) {
  if (l.mon > r.mon)
    return 1;
  if (l.mon == r.mon && l.sum < r.sum)
    return 1;
  return 0;
}

void dpset();
void solve();

souv memo[105];
table dp[105][1000 * 102];
int n;

int main() {
  int i;
  table ans;
  while (1) {
    cin >> n;
    if (n == 0)
      break;
    for (i = 1; i <= n; i++) {
      cin >> memo[i].v;
      memo[i].cha = 1000 - (memo[i].v % 1000);
      if (memo[i].cha == 1000)
        memo[i].cha = 0;
    }
    dpset();
    solve();
    ans.mon = 0;
    ans.sum = inf;
    for (i = 0; i <= n * 1000; ++i)
      if (cmp(dp[n][i], ans))
        ans = dp[n][i];
    if (ans.sum == inf)
      ans.sum = 0;
    cout << ans.mon << " " << ans.sum << endl;
  }
  return 0;
}

void dpset() {
  for (int i = 0; i <= n; ++i)
    for (int j = 0; j <= (n + 1) * 1000; ++j) {
      dp[i][j].mon = 0;
      if (j == 0)
        dp[i][j].sum = 0;
      else
        dp[i][j].sum = inf;
    }
}

void solve() {
  int i, j;
  table now;
  for (i = 1; i <= n; ++i) {
    for (j = 0; j <= n * 1000; ++j) {
      // 札払いでおつりが500超えるので確実に購入
      if (memo[i].cha >= 500 && j >= memo[i].cha % 500 &&
          dp[i - 1][j - memo[i].cha % 500].sum != inf) {
        dp[i][j] = dp[i - 1][j - memo[i].cha % 500];
        ++dp[i][j].mon;
        if (dp[i][j].sum == inf)
          dp[i][j].sum = 0;
        dp[i][j].sum += memo[i].v;
      }
      // 札払いでおつりが500を超えない
      else if (memo[i].cha < 500) {
        // 購入しない
        dp[i][j] = dp[i - 1][j];
        // 端数使って枚数増やすパターン
        if (dp[i - 1][j + (500 - memo[i].cha)].sum != inf) {
          now = dp[i - 1][j + (500 - memo[i].cha)];
          ++now.mon;
          now.sum += memo[i].v;
          if (cmp(now, dp[i][j]))
            dp[i][j] = now;
        }
        // 端数増やすパターン
        if (j >= memo[i].cha && memo[i].cha != 0 &&
            dp[i - 1][j - memo[i].cha].sum != inf) {
          now = dp[i - 1][j - memo[i].cha];
          if (now.sum == inf)
            now.sum = 0;
          now.sum += memo[i].v;
          if (cmp(now, dp[i][j]))
            dp[i][j] = now;
        }
      }
      // if(dp[i][j].sum!=inf)cout << dp[i][j].sum << " " << dp[i][j].mon<<" " ;
    }
  }
}


Error: MLE

Fixed submission:

#include <bits/stdc++.h>
#define inf 99999999
using namespace std;

typedef struct {
  int v;
  int cha;
} souv;
typedef struct {
  int v;
  int cnt;
  bool use[105];
} dp;

souv memo[105];
dp ans[105][51005];
int n;
void solve();
void infset();

int main() {
  int answer = 0;
  int i;
  while (1) {
    vector<int> dummy;
    cin >> n;
    if (n == 0)
      break;
    answer = 0;
    for (i = 0; i < n; i++) {
      cin >> memo[i].v;
      memo[i].cha = 1000 - (memo[i].v % 1000);
      if (memo[i].cha == 1000) {
        memo[i].cha = 0;
        // dummy.push_back(memo[i].v);
      }
    }
    infset();
    solve();
    // for(int j=0;j<=n*500;j++)if(ans[n][j]!=inf)cout <<n << " "<<j <<" "<<
    // ans[n][j] <<endl; cout << ans[n][1500] << endl;
    for (i = 0; i <= (n + 2) * 500; i++) {
      if (ans[n][i].v == inf)
        continue;
      if (i / 500 > answer / 500)
        answer = i;
      else if ((i / 500 == answer / 500) && ans[n][i].v < ans[n][answer].v)
        answer = i;
      // break;
    }
    if (!dummy.empty())
      sort(dummy.begin(), dummy.end());
    // cout << ans[n][answer].cnt;
    // for(i=0;i<n;i++)cout<< ans[n][answer].use[i]<<" ";
    for (i = 0; i < n; i++)
      if (!ans[n][answer].use[i])
        dummy.push_back(memo[i].v);
    if (!dummy.empty())
      sort(dummy.begin(), dummy.end());
    i = 0;
    // cout << ans[n][answer].cnt <<" "<< answer <<" " <<n;
    while (answer / 500 > ans[n][answer].cnt && n > ans[n][answer].cnt) {
      // cout << dummy[i];
      ans[n][answer].v += dummy[i];
      ans[n][answer].cnt++;
      i++;
    }
    cout << min(n, answer / 500) << " " << ans[n][answer].v << endl;
  }
  return 0;
}

void solve() {
  int i, j;
  for (i = 0; i < n; i++)
    for (j = 0; j <= (n + 2) * 500; j++) {
      // cout << j << " " << memo[i].cha<<endl;
      if (j < memo[i].cha) {
        ans[i + 1][j] = ans[i][j];
      } else {
        // ans[i+1][j].v=min(ans[i][j].v,ans[i][j-memo[i].cha].v+memo[i].v);
        if (ans[i][j].v <= ans[i][j - memo[i].cha].v + memo[i].v)
          ans[i + 1][j] = ans[i][j];
        else {
          ans[i + 1][j] = ans[i][j - memo[i].cha];
          ans[i + 1][j].v += memo[i].v;
          ans[i + 1][j].cnt++;
          ans[i + 1][j].use[i] = 1;
        }
      }
    }
}
void infset() {
  int i, j;
  ans[0][0].cnt = 0;
  ans[0][0].v = 0;
  for (i = 0; i < n; i++)
    ans[0][0].use[i] = 0;
  for (j = 1; j <= (n + 2) * 500; j++) {
    ans[0][j].v = inf;
    ans[0][j].cnt = -1;
  }
}