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

#include <bits/stdc++.h>
#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define REP(i, n) FOR(i, 0, n)
#define all(x) (x).begin(), (x).end()
#define bit(x) (1L << (x))
using ll = long long;
using namespace std;

template <typename T> vector<T> make_v(size_t a, T b) {
  return vector<T>(a, b);
}

template <typename... Ts> auto make_v(size_t a, Ts... ts) {
  return vector<decltype(make_v(ts...))>(a, make_v(ts...));
}

class state {
private:
  static int st_pow(int i) {
    static unordered_map<int, int> pow; // memo
    if (pow[i])
      return pow[i];

    if (i == 0) {
      return pow[i] = 1;
    } else {
      return pow[i] = n * st_pow(i - 1);
    }
  }

public:
  static constexpr int n = 3;

  array<deque<int>, n> trays;

  vector<int> get_neighbor() {
    vector<int> ret;

    REP(i, n) {
      if (trays[i].empty())
        continue;

      if (i != 0) { // not left side
        if (trays[i - 1].empty() || trays[i - 1].back() < trays[i].back()) {
          state n_st = *this;
          n_st.trays[i - 1].push_back(n_st.trays[i].back());
          n_st.trays[i].pop_back();
          ret.push_back(encode(n_st));
        }
      }

      if (i != n - 1) { // not right side
        if (trays[i + 1].empty() || trays[i + 1].back() < trays[i].back()) {
          state n_st = *this;
          n_st.trays[i + 1].push_back(n_st.trays[i].back());
          n_st.trays[i].pop_back();
          ret.push_back(encode(n_st));
        }
      }
    }

    return ret;
  }

  void print() const { // for debug
    cout << "================" << endl;
    REP(i, n) {
      cout << "cup: " << i + 1 << endl;
      for (int cup : trays[i]) {
        cout << cup << " ";
      }
      cout << endl;
    }
  }

  static int encode(const state &st) { // state => int
    int ret = 0;

    REP(i, n) {
      for (int cup : st.trays[i]) {
        ret += st_pow(cup) * i;
      }
    }

    return ret;
  }

  static state decode(int cups, int num) { // int => state
    state st;

    for (int i = 0; i < cups; i++) {
      st.trays[num % n].push_back(i);
      num /= n;
    }

    return st;
  }

  static bool is_moderate(const int cups, const state &st) {
    return st.trays[0].size() == cups || st.trays[n - 1].size() == cups;
  }

  static int solve(const int cups, const int max, const state &st) {
    queue<int> q;
    vector<int> score(st_pow(cups), -1);

    int e_st = encode(st);
    q.push(e_st);
    score[e_st] = 0;

    while (!q.empty()) { // bfs
      int e_now = q.front();
      q.pop();
      state now = decode(cups, e_now);

      if (score[e_now] == max)
        continue;

      if (is_moderate(cups, now)) { // return ans
        return score[e_now];
      }

      for (const int e_neighbor : now.get_neighbor()) {
        if (score[e_neighbor] == -1) {
          q.push(e_neighbor);
          score[e_neighbor] = score[e_now] + 1;
        }
      }
    }

    return -1; // not found
  }
};

int main() {
  int n, m;
  while (cin >> n >> m, n && m) {
    state st;
    REP(i, state::n) {
      int c;
      cin >> c;
      REP(j, c) {
        int num;
        cin >> num;
        --num;
        st.trays[i].push_back(num);
      }
    }
    cout << state::solve(n, m, st) << endl;
  }

  return 0;
}


Error: MLE

Fixed submission:

#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <stack>
#include <vector>
using namespace std;

class state {
public:
  stack<int> tray[3];
  int cnt;
  int st;
  state(stack<int> a, stack<int> b, stack<int> c, int cnt) {
    // tray = new stack<int>[3];
    tray[0] = a;
    tray[1] = b;
    tray[2] = c;
    this->cnt = cnt;
  }

  state() {
    // tray = new stack<int>[3];
    cnt = 0;
    st = 0;
  }

  state(const state &ob) {
    // tray = new stack<int>[3];
    for (int i = 0; i < 3; i++)
      tray[i] = ob.tray[i];
    cnt = ob.cnt;
    st = ob.st;
  }

  bool operator<(const state &s) const { return st < s.st; }

  void init() {
    for (int i = 0; i < 3; i++) {
      int n;
      cin >> n;
      int cup;
      for (int j = 0; j < n; j++) {
        cin >> cup;
        tray[i].push(cup);
        st += i * my_pow(cup);
      }
    }
  }

  // i番目のトレイからj番目に移動できるかを返す
  bool canChange(int i, int j) {
    int sizei = tray[i].size(), sizej = tray[j].size();
    if (sizei == 0)
      return false;
    if (sizej == 0)
      return true;

    if (tray[i].top() > tray[j].top())
      return true;
    else
      return false;
  }

  // i番目のトレイのカップをj番目のトレイに入れ替えたstateを返す
  state change(int i, int j) {
    state ex = state(tray[0], tray[1], tray[2], cnt + 1);
    int cup = ex.tray[i].top();
    ex.tray[i].pop();
    ex.tray[j].push(cup);

    ex.st += (-i + j) * my_pow(cup);

    return ex;
  }

private:
  // return pow(3, n)
  int my_pow(int n) {
    int ans = 1;
    for (int i = 0; i < n; i++)
      ans *= 3;
    return ans;
  }
};

int solve(int, int, state);

int main() {
  int n, m; // カップ数 手数
  while (cin >> n >> m, n != 0 && m != 0) {
    state first;
    first.init();
    int dis = solve(n, m, first);
    cout << dis << endl;
  }

  return 0;
}

int solve(int n, int m, state first) {
  queue<state> q;
  q.push(first);
  map<state, bool> mp;

  int ans = -1;

  while (!q.empty()) {
    state now = q.front();
    q.pop();
    // もし手数をオーバーしたなら、-1を格納して終了
    if (now.cnt > m) {
      ans = -1;
      break;
    }

    // もし条件を満たしているなら、手数を格納して終了
    if (now.tray[0].size() == n || now.tray[2].size() == n) {
      ans = now.cnt;
      break;
    }

    // 隣り合う2つのカップで移動
    for (int i = 0; i < 2; i++) {
      if (now.canChange(i, i + 1)) {
        state next = now.change(i, i + 1);
        // もし調査済みならcontinue
        if (mp[next])
          continue;
        mp[next] = true;
        q.push(next);
      }
      if (now.canChange(i + 1, i)) {
        state next = now.change(i + 1, i);
        // もし調査済みならcontinue
        if (mp[next])
          continue;
        mp[next] = true;
        q.push(next);
      }
    }
  }

  return ans;
}