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

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;

int H, W;
char board[15][15];
using Board = map<string, map<int, int>>;
void chmax(int &A, int B) { A = max(A, B); }

string get_uni(string s, int x, int mode) {
  vector<int> v(10), checked(10);
  iota(v.begin(), v.end(), 0);
  if (mode == 1) {
    if (x != 0 && isdigit(s[x]) && isdigit(s[x - 1])) {
      int a = s[x] - '0', b = s[x - 1] - '0';
      v[a] = b;
    } else {
      bool exist_num = false;
      if (x != 0 && isdigit(s[x - 1])) {
        exist_num = true;
        s[x] = s[x - 1];
      }
      if (isdigit(s[x])) {
        exist_num = true;
      }

      if (!exist_num) {
        s[x] = '8';
      }
    }
  }

  string ret = "";
  int id = 0;
  for (int i = 0; i < W; i++) {
    if (isdigit(s[i])) {
      int val = v[s[i] - '0'];
      if (!checked[val])
        checked[val] = ++id;
      ret += (char)('0' + checked[val]);
    } else {
      ret += s[i];
    }
  }
  return ret;
}

bool valid(string s) {
  int pre = -1;
  for (auto c : s) {
    if (isdigit(c)) {
      if (pre == -1)
        pre = c - '0';
      else if (pre != c - '0')
        return false;
    }
  }
  return true;
}

string to_bin(int N) {
  string ret = "";
  for (int i = 0; i < W; i++, N >>= 1) {
    int c = (N & 1);
    ret += (char)('0' + c);
  }
  return ret;
}

int main() {
  scanf("%d%d", &H, &W);
  for (int i = 0; i < H; i++) {
    for (int j = 0; j < W; j++) {
      scanf(" %c", &board[i][j]);
    }
  }

  string emp_str(W, '.');
  Board cur, nxt;
  cur[emp_str][0] = 0;

  for (int pos = 0; pos < H * W; pos++) {
    int row = pos / W, col = pos % W;
    char c = board[row][col];
    for (auto x : cur) {
      string uni = x.first;
      for (auto y : cur[uni]) {
        int bit = y.first, pre = y.second;
        // printf("row = %d, col = %d, dp[%s][%s] = %d\\n", row+1, col+1,
        // uni.c_str(), to_bin(bit).c_str(), pre);

        int base = bit - ((bit >> col & 1) << col);

        // paint (black)
        if (c == '#' || c == '?') {
          // printf("cond 1: row = %d, col = %d\\n", row+1, col+1);
          if (col == 0 || (uni[col] != uni[col - 1] || !isdigit(uni[col]))) {
            string tmp = uni;

            // printf("tmp = %s, ", tmp.c_str());
            tmp = get_uni(tmp, col, 1);
            // printf("nxt = %s\\n", tmp.c_str());

            int nbit = base | (1 << col);
            chmax(nxt[tmp][nbit], pre + 1);
          }
        }

        // paint (white)
        if (c == '.' || c == '?') {
          // printf("cond 2: row = %d, col = %d\\n", row+1, col+1);

          bool ok = true;
          if (row != 0 && !(bit >> col & 1))
            ok = false;
          if (col != 0 && !(bit >> (col - 1) & 1))
            ok = false;

          char target = uni[col];
          int cnt = 0;
          for (int i = 0; i < W; i++)
            cnt += (uni[i] == target);
          if (isdigit(target) && cnt == 1 && W != 1)
            ok = false;

          if (ok) {
            string tmp = uni;
            tmp[col] = '.';
            tmp = get_uni(tmp, col, 0);

            int nbit = base;
            chmax(nxt[tmp][nbit], pre);
          }
        }
      }
    }
    cur.clear();
    swap(cur, nxt);
  }

  int ans = -1;
  for (auto x : cur) {
    string uni = x.first;
    if (!valid(uni))
      continue;

    for (auto y : cur[uni]) {
      int val = y.second;
      chmax(ans, val);
    }
  }
  printf("%d\\n", ans);
  return 0;
}


Error: MLE

Fixed submission:

#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;

int H, W;
char board[15][15];
int dp[2][180000][122];

void chmax(int &A, int B) { A = max(A, B); }

int B;
int merge(int A, int i) {
  while (A >= B)
    A -= B;

  int b = A % 3;
  A = A - (A % 3);
  if (b == 1 && i != 0)
    b = 2;
  A = (A + b) * 3 + i;
  return A;
}
int get_head(int A) { return A / B; }
int get_tail(int A) { return A % 3; }
void thr_eval(int val, int &cnt_black, int &cnt_white, int &cnt_adj_b) {
  if (val == 0) {
    cnt_white++;
  }
  if (val == 1) {
    cnt_black++;
  }
  if (val == 2) {
    cnt_black++;
    cnt_adj_b++;
  }
}

int main() {
  scanf("%d%d", &H, &W);
  for (int i = 0; i < H; i++) {
    for (int j = 0; j < W; j++) {
      scanf(" %c", &board[i][j]);
    }
  }

  int P = H * W, Q = H * W;
  B = 1;
  for (int i = 0; i < W - 1; i++)
    B *= 3;

  memset(dp, -1, sizeof(dp));
  dp[0][0][0] = 0;
  for (int pos = 0; pos < P; pos++) {
    int row = pos / W, col = pos % W;
    int cur = pos % 2, nxt = 1 - cur;
    for (int bit = 0; bit < (3 * B); bit++) {
      for (int diff = 0; diff < Q; diff++) {
        if (dp[cur][bit][diff] < 0)
          continue;

        int val = dp[cur][bit][diff];

        int cnt_black = 0, cnt_white = 0, cnt_adj_b = 0;
        // 真上
        if (row != 0) {
          int val = get_head(bit);
          thr_eval(val, cnt_black, cnt_white, cnt_adj_b);
        }
        // 左隣
        if (col != 0) {
          int val = get_tail(bit);
          thr_eval(val, cnt_black, cnt_white, cnt_adj_b);
        }

        char c = board[row][col];
        if (c == '#' || c == '?') {
          int n_diff = diff + 1 - cnt_black;
          int n_self = (cnt_black ? 2 : 1);
          if (n_diff > 0) {
            int nbit = merge(bit, n_self);
            chmax(dp[nxt][nbit][n_diff], val + 1);
          }
        }
        if (c == '.' || c == '?') {
          if (row != 0) {
            if (get_head(bit) == 1)
              continue;
          }
          if (row == W - 1) {
            if (get_tail(bit) == 1)
              continue;
          }

          if (cnt_white == 0) {
            int nbit = merge(bit, 0);
            chmax(dp[nxt][nbit][diff], val);
          }
        }

        dp[cur][bit][diff] = -1;
      }
    }
  }

  int ans = -1;
  for (int bit = 0; bit < 3 * B; bit++) {
    if (dp[P % 2][bit][1] < 0)
      continue;
    chmax(ans, dp[P % 2][bit][1]);
  }
  printf("%d\\n", ans);
  return 0;
}