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

#include <array>
#include <cassert>
#include <cmath>
#include <cstring>
#include <iostream>
#include <string>

int blocks[300];
int8_t strike_range[300][300];
int score_in_range[300][300];

const int8_t STRIKE_RANGE_UNDEF = 0;
const int8_t STRIKE_RANGE_NO = 1;
const int8_t STRIKE_RANGE_YES = 2;

bool can_strike(int x, int y) { return std::abs(blocks[x] - blocks[y]) <= 1; }

int8_t search_range(int start, int end) {
  if (start >= end)
    return STRIKE_RANGE_UNDEF;
  if ((end - start + 1) % 2 != 0)
    return STRIKE_RANGE_NO;

  int8_t *p = &strike_range[start][end];
  if (*p != STRIKE_RANGE_UNDEF)
    return *p;

  if (start + 1 == end)
    return *p = can_strike(start, end) ? STRIKE_RANGE_YES : STRIKE_RANGE_NO;

  for (int i = start + 1; i < end - 1; i++) {
    if (search_range(start, i) == STRIKE_RANGE_YES &&
        search_range(i + 1, end) == STRIKE_RANGE_YES) {
      return *p = STRIKE_RANGE_YES;
    }
  }

  auto result = search_range(start + 1, end - 1);
  return *p = result == STRIKE_RANGE_YES && can_strike(start, end)
                  ? STRIKE_RANGE_YES
                  : STRIKE_RANGE_NO;
}

int main() {
  while (true) {
    int n;
    std::cin >> n;

    if (n == 0)
      return 0;

    for (int i = 0; i < n; i++) {
      int w;
      std::cin >> w;
      blocks[i] = w;
    }

    std::memset(strike_range, 0, sizeof(strike_range));

    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n; j++) {
        score_in_range[i][j] =
            search_range(i, j) == STRIKE_RANGE_YES ? j - i + 1 : 0;
      }
    }

    for (int i = 0; i < n; i++) {
      for (int j = i; j < n; j++) {
        for (int k = i; k < j; k++) {
          score_in_range[i][j] =
              std::max(score_in_range[i][j],
                       score_in_range[i][k] + score_in_range[k + 1][j]);
        }
      }
    }

    std::cout << score_in_range[0][n - 1] << std::endl;
  }
}

Error: MLE

Fixed submission:

#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <vector>

struct Context {
  std::vector<int> &blocks;
  std::unordered_map<uint64_t, int> cache;
};

struct State {
  uint64_t data;

  State() : data(0) {}
  State(uint64_t data) : data(data) {}

  State mark(int index) { return data | (((uint64_t)1) << index); }

  bool is_marked(int index) { return (data & (((uint64_t)1) << index)) != 0; }
};

int search(Context &ctx, State state, int count) {
  if (ctx.blocks.size() == 0)
    return count;
  auto cache_iter = ctx.cache.find(state.data);
  if (cache_iter != ctx.cache.end())
    return (*cache_iter).second;

  int max = count;

  for (int i = 0; i < ctx.blocks.size() - 1; i++) {
    if (state.is_marked(i))
      continue;

    // ?¬????????????????????????¢???
    for (int j = i + 1; j < ctx.blocks.size(); j++) {
      if (state.is_marked(j))
        continue;
      if (std::abs(ctx.blocks[i] - ctx.blocks[j]) > 1)
        break;

      int result = search(ctx, state.mark(i).mark(j), count + 2);
      if (result > max)
        max = result;
    }
  }

  ctx.cache[state.data] = max;
  return max;
}

int main() {
  std::vector<int> blocks;
  blocks.reserve(300);

  while (true) {
    int num_blocks;
    std::cin >> num_blocks;

    if (num_blocks == 0)
      return 0;

    blocks.clear();
    for (int i = 0; i < num_blocks; i++) {
      int w;
      std::cin >> w;
      blocks.push_back(w);
    }

    Context ctx{blocks, {}};
    std::cout << search(ctx, {}, 0) << std::endl;
  }
}