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

#include <bits/stdc++.h>
#define show(x) cerr << #x << " = " << (x) << endl
using namespace std;
template <typename Functor> struct fix_type {
  Functor functor;
  template <typename... Args>
  decltype(auto) operator()(Args &&...args) const & {
    return functor(functor, std::forward<Args>(args)...);
  }
};
template <typename Functor>
fix_type<typename std::decay<Functor>::type> fix(Functor &&functor) {
  return {std::forward<Functor>(functor)};
}
template <typename T> vector<T> Vec(int n, T v) { return vector<T>(n, v); }
template <class... Args> auto Vec(int n, Args... args) {
  auto val = Vec(args...);
  return vector<decltype(val)>(n, move(val));
}

int main() {
  while (true) {
    int H, W;
    cin >> H >> W;
    if (H == 0 and W == 0) {
      break;
    }
    auto C = Vec(H, W, char(0));
    auto I = Vec(H, W, -1);
    using P = pair<int, int>;
    auto in = [&](const int y, const int x) {
      return y >= 0 and y < H and x >= 0 and x < W and C[y][x] != '#';
    };
    vector<P> pos[26]{}, POS[26]{};
    for (int i = 0; i < H; i++) {
      for (int j = 0; j < W; j++) {
        cin >> C[i][j];
        if (islower(C[i][j])) {
          const int c = C[i][j] - 'a';
          pos[c].push_back({i, j});
          I[i][j] = pos[c].size() - 1;
        } else if (isupper(C[i][j])) {
          const int c = C[i][j] - 'A';
          POS[c].push_back({i, j});
          I[i][j] = POS[c].size() - 1;
        }
      }
    }
    auto bfs = [&](const int y, const int x) {
      auto used = Vec(H, W, false);
      queue<P> q;
      q.push({y, x}), used[y][x] = true;
      while (not q.empty()) {
        const int y = q.front().first, x = q.front().second;
        q.pop();
        if (in(y + 1, x) and not used[y + 1][x]) {
          q.push({y + 1, x}), used[y + 1][x] = true;
        }
        if (in(y, x + 1) and not used[y][x + 1]) {
          q.push({y, x + 1}), used[y][x + 1] = true;
        }
      }
      return used;
    };
    if (not bfs(0, 0)[H - 1][W - 1]) {
      cout << -1 << endl;
      continue;
    }
    vector<vector<bool>> ok[26];
    for (int i = 0; i < 26; i++) {
      const int S = pos[i].size(), T = POS[i].size();
      ok[i] = Vec(S, T, false);
      for (int j = 0; j < S; j++) {
        const auto used = bfs(pos[i][j].first, pos[i][j].second);
        for (int k = 0; k < T; k++) {
          ok[i][j][k] = used[POS[i][k].first][POS[i][k].second];
        }
      }
    }
    auto memo = Vec(H, W, H, W, -1);
    constexpr int INF = 1 << 30;
    auto solve = fix([&](auto &&self, const int y1, const int x1, const int y2,
                         const int x2) -> int {
      if (not in(y1, x1) or not in(y2, x2) or y2 < y1 or x2 < x1) {
        return -INF;
      }
      if (y1 == y2 and x1 == x2) {
        return memo[y1][x1][y2][x2] = 0;
      }
      if (memo[y1][x1][y2][x2] != -1) {
        return memo[y1][x1][y2][x2];
      }
      int ans =
          max(self(self, y1 + 1, x1, y2, x2), self(self, y1, x1 + 1, y2, x2));
      if (islower(C[y1][x1]) == 0) {
        return memo[y1][x1][y2][x2] = ans;
      }
      const int c = C[y1][x1] - 'a', ind = I[y1][x1];
      for (int j = 0; j < POS[c].size(); j++) {
        if (ok[c][ind][j]) {
          const int D = abs(POS[c][j].first - y1) + abs(POS[c][j].second - x1);
          const int after =
              self(self, POS[c][j].first, POS[c][j].second, y2, x2);
          const int before =
              D == 1 ? 0
                     : max({self(self, y1 + 1, x1, POS[c][j].first - 1,
                                 POS[c][j].second),
                            self(self, y1, x1 + 1, POS[c][j].first - 1,
                                 POS[c][j].second),
                            self(self, y1 + 1, x1, POS[c][j].first,
                                 POS[c][j].second - 1),
                            self(self, y1, x1 + 1, POS[c][j].first,
                                 POS[c][j].second - 1)});
          ans = max(ans, before + after + 1);
        }
      }
      return memo[y1][x1][y2][x2] = ans;
    });
    cout << solve(0, 0, H - 1, W - 1) << endl;
  }
  return 0;
}


Error: MLE

Fixed submission:

#include <bits/stdc++.h>
#define show(x) cerr << #x << " = " << (x) << endl
using namespace std;
template <typename Functor> struct fix_type {
  Functor functor;
  template <typename... Args>
  decltype(auto) operator()(Args &&...args) const & {
    return functor(functor, std::forward<Args>(args)...);
  }
};
template <typename Functor>
fix_type<typename std::decay<Functor>::type> fix(Functor &&functor) {
  return {std::forward<Functor>(functor)};
}
int main() {
  auto lower = [](const char c) -> bool { return c >= 'a' and c <= 'z'; };
  auto toLower = [](const char c) -> char { return (char)(c - 'A' + 'a'); };
  while (true) {
    int H, W;
    cin >> H >> W;
    if (H == 0 and W == 0) {
      break;
    }
    vector<vector<char>> C(H, vector<char>(W));
    for (int i = 0; i < H; i++) {
      for (int j = 0; j < W; j++) {
        cin >> C[i][j];
      }
    }
    using P = pair<string, pair<int, int>>;
    map<P, int> memo;
    constexpr int INF = 1 << 30;
    auto rec = fix([&](auto &&self, const P &p) -> int {
      string s = p.first;
      const int y = p.second.first, x = p.second.second;
      if ((y == H and x == W - 1) or (y == H - 1 and x == W)) {
        return 0;
      }
      if (y < 0 or y >= H or x < 0 or x >= W or C[y][x] == '#') {
        return -INF;
      }
      if (memo.find(p) != memo.end()) {
        return memo[p];
      }
      if (C[y][x] == '.') {
        return memo[p] = max(self(self, {s, {y + 1, x}}),
                             self(self, {s, {y, x + 1}}));
      } else {
        if (lower(C[y][x])) {
          s.push_back(C[y][x]);
          return memo[p] = max(self(self, {s, {y + 1, x}}),
                               self(self, {s, {y, x + 1}}));
        } else {
          const char low = toLower(C[y][x]);
          if (s.back() == low) {
            s.pop_back();
            return memo[p] = 1 + max(self(self, {s, {y + 1, x}}),
                                     self(self, {s, {y, x + 1}}));
          }
          int ans =
              max(self(self, {s, {y + 1, x}}), self(self, {s, {y, x + 1}}));
          for (; not s.empty() and s.back() != low; s.pop_back()) {
          }
          if (s.empty()) {
            return memo[p] = ans;
          } else {
            s.pop_back();
            return memo[p] = max(ans, 1 + max(self(self, {s, {y + 1, x}}),
                                              self(self, {s, {y, x + 1}})));
          }
        }
      }
    });
    const P start = {"", {0, 0}};
    const int ans = rec(start);
    cout << max(-1, ans) << endl;
  }
  return 0;
}