Problem p02637 (C++)

Buggy submission (status: Runtime Error):
#include <algorithm>
#include <cassert>
#include <cstring>
#include <iostream>
#include <set>
#include <vector>

#define TRACE(x) std::cout << #x << " = " << x << "\n"
#define _ << " _ " <<

using namespace std;

bool possiblePrefix(vector<pair<int, int>> A, vector<int> prefix) {
  int K = A.size();
  vector<int> where(K);
  for (int i = 0; i < K; ++i)
    where[A[i].second] = i;
  for (int x : prefix)
    A[where[x]].first++;

  sort(A.begin(), A.end());
  if (A[0].first * 2 < A.back().first)
    return false;

  vector<bool> isOne(K, false), isTwo(K, false);
  int min = A[0].first, nTwos = 0;
  for (int i = 0; i < K; ++i) {
    if (min * 2 == A[i].first) {
      isTwo[A[i].second] = true;
      nTwos++;
    }
    if (min == A[i].first)
      isOne[A[i].second] = true;
  }
  reverse(prefix.begin(), prefix.end());
  while (prefix.size() && isTwo[prefix.back()]) {
    nTwos--;
    prefix.pop_back();
  }
  if (!nTwos)
    return true;
  for (int x : prefix)
    if (isOne[x])
      return false;
  return true;
}

bool possible(vector<pair<int, int>> A, const vector<int> &suffix) {
  int K = A.size();
  vector<int> where(K);
  for (int i = 0; i < K; ++i)
    where[A[i].second] = i;

  for (int i = 0; i < K; ++i) {
    if (possiblePrefix(A, {}))
      return true;
    int j = where[suffix[i]];
    if (A[j].first == 0)
      break;
    A[j].first--;
  }
  return false;
}

bool possibleFinish(vector<pair<int, int>> A, vector<int> &B, int coveredUpTo) {
  int K = A.size();
  vector<bool> seen(K, false);
  vector<int> prefix;
  if (B.size()) {
    for (int32_t i = B.size() - 1; i >= 0; --i) {
      if (seen[B[i]]) {
        if (coveredUpTo <= i)
          return false;
        break;
      }
      prefix.push_back(B[i]);
      seen[B[i]] = true;
    }
  }
  reverse(prefix.begin(), prefix.end());
  if ((int)prefix.size() == K)
    return possible(A, prefix);
  while (coveredUpTo + prefix.size() >= B.size()) {
    if (possiblePrefix(A, prefix))
      return true;
    if (prefix.size()) {
      prefix.erase(prefix.begin());
    } else {
      break;
    }
  }
  return false;
}

int main() {
  std::ios_base::sync_with_stdio(false);

  int K;
  cin >> K;
  vector<pair<int, int>> A;
  for (int i = 0; i < K; ++i) {
    int x;
    cin >> x;
    A.emplace_back(x, i);
  }

  sort(A.begin(), A.end());
  vector<int> B;

  if (!possibleFinish(A, B, 0)) {
    cout << "-1\n";
    return 0;
  }

  int coveredUpTo = 0;
  while (true) {
    int tot = 0;
    for (auto &p : A)
      tot += p.first;
    if (tot == 0)
      break;

    vector<int> where(K);
    for (int i = 0; i < K; ++i)
      where[A[i].second] = i;

    int x = -1;
    for (int i = 0; i < K; ++i) {
      if (A[where[i]].first == 0)
        continue;

      A[where[i]].first--;
      B.push_back(i);
      if (possibleFinish(A, B, coveredUpTo)) {
        x = i;
        break;
      }
      B.pop_back();
      A[where[i]].first++;
    }
    assert(x != -1);
    if (B.size() >= K) {
      vector<int> p(B.end() - K, B.end());
      sort(p.begin(), p.end());
      bool isPerm = true;
      for (int i = 0; i < K; ++i)
        isPerm &= p[i] == i;
      if (isPerm) {
        assert(coveredUpTo + K >= B.size());
        coveredUpTo = B.size();
      }
    }
  }

  assert(coveredUpTo == B.size());
  for (int x : B)
    cout << x + 1 << ' ';
  cout << '\n';
  return 0;
}


Fixed submission:
#include <algorithm>
#include <cassert>
#include <cstring>
#include <iostream>
#include <set>
#include <vector>

#define TRACE(x) std::cout << #x << " = " << x << "\n"
#define _ << " _ " <<

using namespace std;

bool possiblePrefix(vector<pair<int, int>> A, vector<int> prefix) {
  int K = A.size();
  vector<int> where(K);
  for (int i = 0; i < K; ++i)
    where[A[i].second] = i;
  for (int x : prefix)
    A[where[x]].first++;

  sort(A.begin(), A.end());
  if (A[0].first * 2 < A.back().first)
    return false;

  vector<bool> isOne(K, false), isTwo(K, false);
  int min = A[0].first, nTwos = 0;
  for (int i = 0; i < K; ++i) {
    if (min * 2 == A[i].first) {
      isTwo[A[i].second] = true;
      nTwos++;
    }
    if (min == A[i].first)
      isOne[A[i].second] = true;
  }
  reverse(prefix.begin(), prefix.end());
  while (prefix.size() && !isOne[prefix.back()]) {
    if (isTwo[prefix.back()])
      nTwos--;
    prefix.pop_back();
  }
  if (!nTwos)
    return true;
  for (int x : prefix)
    if (isOne[x])
      return false;
  return true;
}

bool possible(vector<pair<int, int>> A, const vector<int> &suffix) {
  int K = A.size();
  vector<int> where(K);
  for (int i = 0; i < K; ++i)
    where[A[i].second] = i;

  for (int i = 0; i < K; ++i) {
    if (possiblePrefix(A, {}))
      return true;
    int j = where[suffix[i]];
    if (A[j].first == 0)
      break;
    A[j].first--;
  }
  return false;
}

bool possibleFinish(vector<pair<int, int>> A, vector<int> &B, int coveredUpTo) {
  int K = A.size();
  vector<bool> seen(K, false);
  vector<int> prefix;
  if (B.size()) {
    for (int32_t i = B.size() - 1; i >= 0; --i) {
      if (seen[B[i]]) {
        if (coveredUpTo <= i)
          return false;
        break;
      }
      prefix.push_back(B[i]);
      seen[B[i]] = true;
    }
  }
  reverse(prefix.begin(), prefix.end());
  if ((int)prefix.size() == K)
    return possible(A, prefix);
  while (coveredUpTo + prefix.size() >= B.size()) {
    if (possiblePrefix(A, prefix))
      return true;
    if (prefix.size()) {
      prefix.erase(prefix.begin());
    } else {
      break;
    }
  }
  return false;
}

int main() {
  std::ios_base::sync_with_stdio(false);

  int K;
  cin >> K;
  vector<pair<int, int>> A;
  for (int i = 0; i < K; ++i) {
    int x;
    cin >> x;
    A.emplace_back(x, i);
  }

  sort(A.begin(), A.end());
  vector<int> B;

  if (!possibleFinish(A, B, 0)) {
    cout << "-1\n";
    return 0;
  }

  int coveredUpTo = 0;
  while (true) {
    int tot = 0;
    for (auto &p : A)
      tot += p.first;
    if (tot == 0)
      break;

    vector<int> where(K);
    for (int i = 0; i < K; ++i)
      where[A[i].second] = i;

    int x = -1;
    for (int i = 0; i < K; ++i) {
      if (A[where[i]].first == 0)
        continue;

      A[where[i]].first--;
      B.push_back(i);
      if (possibleFinish(A, B, coveredUpTo)) {
        x = i;
        break;
      }
      B.pop_back();
      A[where[i]].first++;
    }
    assert(x != -1);
    if (B.size() >= K) {
      vector<int> p(B.end() - K, B.end());
      sort(p.begin(), p.end());
      bool isPerm = true;
      for (int i = 0; i < K; ++i)
        isPerm &= p[i] == i;
      if (isPerm) {
        assert(coveredUpTo + K >= B.size());
        coveredUpTo = B.size();
      }
    }
  }

  assert(coveredUpTo == B.size());
  for (int x : B)
    cout << x + 1 << ' ';
  cout << '\n';
  return 0;
}