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

#include <cstdio>
#include <queue>
#include <set>

#define rep(i, n) for (int i = 0; i < (n); i++)

using namespace std;

typedef long long ll;

const int dx[] = {1, 0, -1, 0}, dy[] = {0, -1, 0, 1};

ll to_ll(const int a[4][4]) {
  ll res = 0;
  rep(i, 4) rep(j, 4) res |= (ll)a[i][j] << 3 * (i * 4 + j);
  return res;
}

void burst(const int a[4][4], int b[4][4]) {
  rep(i, 4) rep(j, 4) b[i][j] = a[i][j];

  bool drop[4][4][4] = {};
  while (1) {
    bool next[4][4][4] = {};
    rep(k, 4) rep(i, 4) rep(j, 4) if (drop[k][i][j]) {
      int y = i + dy[k], x = j + dx[k];
      if (0 <= y && y < 4 && 0 <= x && x < 4) {
        if (b[y][x] == 0) {
          next[k][y][x] = true;
        } else {
          b[y][x]++;
        }
      }
    }

    bool end = true;
    rep(i, 4) rep(j, 4) if (b[i][j] >= 5) {
      end = false;
      b[i][j] = 0;
      rep(k, 4) next[k][i][j] = true;
    }
    rep(k, 4) rep(i, 4) rep(j, 4) {
      drop[k][i][j] = next[k][i][j];
      if (next[k][i][j])
        end = false;
    }
    if (end)
      return;
  }
}

int main() {
  ll S0 = 0;
  rep(i, 16) {
    int a;
    scanf("%d", &a);
    S0 |= (ll)a << 3 * i;
  }

  int ans = -1;
  set<ll> memo;
  memo.insert(S0);
  queue<pair<int, ll>> Q;
  Q.push(make_pair(0, S0));
  while (!Q.empty()) {
    int c = Q.front().first;
    ll S = Q.front().second;
    Q.pop();

    if (c > 5)
      break;
    if (S == 0) {
      ans = c;
      break;
    }

    int a[4][4];
    rep(i, 4) rep(j, 4) a[i][j] = (S >> 3 * (i * 4 + j)) & 7;

    rep(i, 4) rep(j, 4) {
      a[i][j]++;

      int a2[4][4];
      burst(a, a2);
      ll S2 = to_ll(a2);

      if (memo.count(S2) == 0) {
        memo.insert(S2);
        Q.push(make_pair(c + 1, S2));
      }

      a[i][j]--;
    }
  }

  printf("%d\\n", ans);

  return 0;
}

Error: MLE

Fixed submission:

#include <cstdio>
#include <queue>
#include <set>

#define rep(i, n) for (int i = 0; i < (n); i++)

using namespace std;

typedef long long ll;

const int dx[] = {1, 0, -1, 0}, dy[] = {0, -1, 0, 1};

ll to_ll(const int a[4][4]) {
  ll res = 0;
  rep(i, 4) rep(j, 4) res |= (ll)a[i][j] << 3 * (i * 4 + j);
  return res;
}

void burst(const int a[4][4], int b[4][4]) {
  rep(i, 4) rep(j, 4) b[i][j] = a[i][j];

  bool drop[4][4][4] = {};
  while (1) {
    bool next[4][4][4] = {};
    rep(k, 4) rep(i, 4) rep(j, 4) if (drop[k][i][j]) {
      int y = i + dy[k], x = j + dx[k];
      if (0 <= y && y < 4 && 0 <= x && x < 4) {
        if (b[y][x] == 0) {
          next[k][y][x] = true;
        } else {
          b[y][x]++;
        }
      }
    }

    bool end = true;
    rep(i, 4) rep(j, 4) if (b[i][j] >= 5) {
      end = false;
      b[i][j] = 0;
      rep(k, 4) next[k][i][j] = true;
    }
    rep(k, 4) rep(i, 4) rep(j, 4) {
      drop[k][i][j] = next[k][i][j];
      if (next[k][i][j])
        end = false;
    }
    if (end)
      return;
  }
}

int main() {
  ll S0 = 0;
  rep(i, 16) {
    int a;
    scanf("%d", &a);
    S0 |= (ll)a << 3 * i;
  }

  int ans;
  set<ll> memo;
  memo.insert(S0);
  queue<pair<int, ll>> Q;
  Q.push(make_pair(0, S0));
  while (!Q.empty()) {
    int c = Q.front().first;
    ll S = Q.front().second;
    Q.pop();

    if (S == 0) {
      ans = c;
      break;
    }

    int a[4][4];
    rep(i, 4) rep(j, 4) a[i][j] = (S >> 3 * (i * 4 + j)) & 7;

    rep(i, 4) rep(j, 4) if (a[i][j] > 0) {
      a[i][j]++;

      int a2[4][4];
      burst(a, a2);
      ll S2 = to_ll(a2);

      if (memo.count(S2) == 0) {
        memo.insert(S2);
        Q.push(make_pair(c + 1, S2));
      }

      a[i][j]--;
    }
  }

  printf("%d\\n", ans);

  return 0;
}