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

#include <algorithm>
#include <array>
#include <cassert>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <valarray>
#include <vector>

using namespace std;
using ll = long long;
using ull = unsigned long long;

using P = array<int, 16>;

constexpr int B = 10;
unordered_map<ull, int> cor_hb[9];

void first() {
  for (int n = 1; n <= 8; n++) {
    auto p2ull = [&](const P &x) {
      ull a = 0;
      for (int i = 0; i < 2 * n; i++) {
        a <<= 4;
        a += x[i];
      }
      return a;
    };
    auto ull2p = [&](ull a) {
      P p = {};
      for (int i = 2 * n - 1; i >= 0; i--) {
        p[i] = a & 0b1111;
        a >>= 4;
      }
      return p;
    };
    using Q = pair<int, ull>;
    P first = {};
    for (int i = 0; i < n; i++) {
      first[2 * i] = first[2 * i + 1] = i;
    }
    queue<Q> que;
    que.push(Q(0, p2ull(first)));
    while (!que.empty()) {
      int dist;
      ull xh;
      tie(dist, xh) = que.front();
      que.pop();
      P x = ull2p(xh);
      if (cor_hb[n].count(xh))
        continue;
      cor_hb[n][xh] = dist;
      if (dist >= B - 1)
        break;
      for (int i = 0; i < n - 1; i++) {
        for (int l = 0; l < 2; l++) {
          for (int r = 0; r < 2; r++) {
            P y = x;
            swap(y[2 * i + l], y[2 * i + 2 + r]);
            if (y[2 * i + 0] > y[2 * i + 1]) {
              swap(y[2 * i + 0], y[2 * i + 1]);
            }
            if (y[2 * i + 2] > y[2 * i + 3]) {
              swap(y[2 * i + 2], y[2 * i + 3]);
            }
            ull yh = p2ull(y);
            if (cor_hb[n].count(yh))
              continue;
            que.push(Q(dist + 1, yh));
          }
        }
      }
    }
  }
}
bool solve() {
  int n;
  cin >> n;
  if (!n)
    return false;
  P a = {};
  for (int i = 0; i < 2 * n; i++) {
    int x;
    cin >> x;
    x--;
    a[i] = x;
  }
  for (int i = 0; i < n; i++) {
    if (a[2 * i] > a[2 * i + 1]) {
      swap(a[2 * i], a[2 * i + 1]);
    }
  }
  if (n == 8) {
    bool allrev = true;
    for (int i = 0; i < n; i++) {
      if (a[2 * i] != n - 1 - i or a[2 * i + 1] != n - 1 - i) {
        allrev = false;
        break;
      }
    }
    if (allrev) {
      cout << 40 << endl;
      return true;
    }
  }
  auto h = [&](const P &x) {
    int sm = 0;
    for (int i = 0; i < n; i++) {
      sm += abs(x[2 * i] - i);
      sm += abs(x[2 * i + 1] - i);
    }
    return sm;
  };
  auto p2ull = [&](const P &x) {
    ull a = 0;
    for (int i = 0; i < 2 * n; i++) {
      a <<= 4;
      a += x[i];
    }
    return a;
  };
  auto ull2p = [&](ull a) {
    P p = {};
    for (int i = 2 * n - 1; i >= 0; i--) {
      p[i] = a & 0b1111;
      a >>= 4;
    }
    return p;
  };
  constexpr int MD = 100;
  unordered_map<ull, int> &cor_h = cor_hb[n];
  // {
  //     using Q = pair<int, P>;
  //     P first = {};
  //     for (int i = 0; i < n; i++) {
  //         first[2*i] = first[2*i+1] = i;
  //     }
  //     queue<Q> que;
  //     que.push(Q(0, first));
  //     while (!que.empty()) {
  //         int dist; P x;
  //         tie(dist, x) = que.front(); que.pop();
  //         if (dist >= B) break;
  //         if (cor_h.count(p2ull(x))) continue;
  //         cor_h[p2ull(x)] = dist;
  //         for (int i = 0; i < n-1; i++) {
  //             for (int l = 0; l < 2; l++) {
  //                 for (int r = 0; r < 2; r++) {
  //                     P y = x;
  //                     swap(y[2*i+l], y[2*i+2+r]);
  //                     if (y[2*i+0] > y[2*i+1]) {
  //                         swap(y[2*i+0], y[2*i+1]);
  //                     }
  //                     if (y[2*i+2] > y[2*i+3]) {
  //                         swap(y[2*i+2], y[2*i+3]);
  //                     }
  //                     que.push(Q(dist+1, y));
  //                 }
  //             }
  //         }
  //     }
  // }
  {
    using Q = pair<int, ull>;
    vector<Q> que[MD];
    que[h(a) / 2].push_back(Q(h(a), p2ull(a)));
    int ans = 10000;
    int gc = 0;
    unordered_set<ull> used;
    for (int disth = 0; disth < MD; disth++) {
      sort(que[disth].begin(), que[disth].end());
      que[disth].erase(unique(begin(que[disth]), end(que[disth])),
                       end(que[disth]));
      while (que[disth].size()) {
        gc++;
        P x;
        ull xhs;
        int hx;
        tie(hx, xhs) = que[disth].back();
        que[disth].pop_back();
        x = ull2p(xhs);
        if (ans <= disth)
          break;
        if (used.count(xhs))
          continue;
        used.insert(xhs);
        if (hx / 2 < B and cor_h.count(xhs)) {
          ans = min(ans, disth - hx / 2 + cor_h[xhs]);
          continue;
        }
        for (int i = 0; i < n - 1; i++) {
          P y = x;
          int hy = hx;
          swap(y[2 * i + 1], y[2 * i + 2]);
          hy -= abs(x[2 * i + 1] - i);
          hy -= abs(x[2 * i + 2] - (i + 1));
          hy += abs(y[2 * i + 1] - i);
          hy += abs(y[2 * i + 2] - (i + 1));
          if (y[2 * i + 0] > y[2 * i + 1]) {
            swap(y[2 * i + 0], y[2 * i + 1]);
          }
          if (y[2 * i + 2] > y[2 * i + 3]) {
            swap(y[2 * i + 2], y[2 * i + 3]);
          }
          //                    assert(disth <= disth-hx/2+1+hy/2);
          int ndisth = disth - hx / 2 + 1 + hy / 2;
          ull yhs = p2ull(y);
          if (ans <= ndisth)
            continue;
          //                    if (used.count(yhs)) continue;
          que[ndisth].push_back(Q(hy, yhs));
        }
      }
    }
    //        cout << ans << " " << used.size() << " " << cor_h.size() << " " <<
    //        gc << endl;
    cout << ans << endl;
  }
  return true;
}

int main() {
  first();
  while (solve()) {
  }
  return 0;
}

Error: MLE

Fixed submission:

#include <algorithm>
#include <array>
#include <cassert>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <valarray>
#include <vector>

using namespace std;
using ll = long long;
using ull = unsigned long long;

using P = array<int, 16>;

bool solve() {
  int n;
  cin >> n;
  if (!n)
    return false;
  P a = {};
  for (int i = 0; i < 2 * n; i++) {
    int x;
    cin >> x;
    x--;
    a[i] = x;
  }
  for (int i = 0; i < n; i++) {
    if (a[2 * i] > a[2 * i + 1]) {
      swap(a[2 * i], a[2 * i + 1]);
    }
  }
  if (n == 8) {
    bool allrev = true;
    for (int i = 0; i < n; i++) {
      if (a[2 * i] != n - 1 - i or a[2 * i + 1] != n - 1 - i) {
        allrev = false;
        break;
      }
    }
    if (allrev) {
      cout << 40 << endl;
      return true;
    }
  }
  auto h = [&](const P &x) {
    int sm = 0;
    for (int i = 0; i < n; i++) {
      sm += abs(x[2 * i] - i);
      sm += abs(x[2 * i + 1] - i);
    }
    return sm;
  };
  auto p2ull = [&](const P &x) {
    ull a = 0;
    for (int i = 0; i < 2 * n; i++) {
      a <<= 4;
      a += x[i];
    }
    return a;
  };
  auto ull2p = [&](ull a) {
    P p = {};
    for (int i = 2 * n - 1; i >= 0; i--) {
      p[i] = a & 0b1111;
      a >>= 4;
    }
    return p;
  };
  constexpr int B = 10;
  constexpr int MD = 100;
  unordered_map<ull, int> cor_h;
  {
    using Q = pair<int, P>;
    P first = {};
    for (int i = 0; i < n; i++) {
      first[2 * i] = first[2 * i + 1] = i;
    }
    queue<Q> que;
    que.push(Q(0, first));
    while (!que.empty()) {
      int dist;
      P x;
      tie(dist, x) = que.front();
      que.pop();
      if (dist >= B)
        break;
      if (cor_h.count(p2ull(x)))
        continue;
      cor_h[p2ull(x)] = dist;
      for (int i = 0; i < n - 1; i++) {
        for (int l = 0; l < 2; l++) {
          for (int r = 0; r < 2; r++) {
            P y = x;
            swap(y[2 * i + l], y[2 * i + 2 + r]);
            if (y[2 * i + 0] > y[2 * i + 1]) {
              swap(y[2 * i + 0], y[2 * i + 1]);
            }
            if (y[2 * i + 2] > y[2 * i + 3]) {
              swap(y[2 * i + 2], y[2 * i + 3]);
            }
            que.push(Q(dist + 1, y));
          }
        }
      }
    }
  }
  {
    using Q = pair<int, ull>;
    vector<Q> que[MD];
    que[h(a) / 2].push_back(Q(h(a), p2ull(a)));
    int ans = 10000;
    int gc = 0;
    unordered_set<ull> used;
    for (int disth = 0; disth < MD; disth++) {
      sort(que[disth].begin(), que[disth].end());
      que[disth].erase(unique(begin(que[disth]), end(que[disth])),
                       end(que[disth]));
      while (que[disth].size()) {
        gc++;
        P x;
        ull xhs;
        int hx;
        tie(hx, xhs) = que[disth].back();
        que[disth].pop_back();
        x = ull2p(xhs);
        if (ans <= disth)
          break;
        if (used.count(xhs))
          continue;
        used.insert(xhs);
        if (hx / 2 < B and cor_h.count(xhs)) {
          ans = min(ans, disth - hx / 2 + cor_h[xhs]);
          continue;
        }
        for (int i = 0; i < n - 1; i++) {
          P y = x;
          int hy = hx;
          swap(y[2 * i + 1], y[2 * i + 2]);
          hy -= abs(x[2 * i + 1] - i);
          hy -= abs(x[2 * i + 2] - (i + 1));
          hy += abs(y[2 * i + 1] - i);
          hy += abs(y[2 * i + 2] - (i + 1));
          if (y[2 * i + 0] > y[2 * i + 1]) {
            swap(y[2 * i + 0], y[2 * i + 1]);
          }
          if (y[2 * i + 2] > y[2 * i + 3]) {
            swap(y[2 * i + 2], y[2 * i + 3]);
          }
          //                    assert(disth <= disth-hx/2+1+hy/2);
          int ndisth = disth - hx / 2 + 1 + hy / 2;
          ull yhs = p2ull(y);
          if (ans <= ndisth)
            continue;
          //                    if (used.count(yhs)) continue;
          que[ndisth].push_back(Q(hy, yhs));
        }
      }
    }
    cout << ans << " " << used.size() << " " << cor_h.size() << " " << gc
         << endl;
  }
  return true;
}

int main() {
  while (solve()) {
  }
  return 0;
}