Skip to content

Double Rainbow boj 23567

Source Code#

#include <algorithm>
#include <cstdint>
#include <iterator>
#include <vector>

#define cr const &

using std::vector;
using Vec = vector<int>;

constexpr size_t INV = (1 << 30) - 1;

inline bool is_rainbow(Vec cr sequence) {
  return std::all_of(sequence.begin(), sequence.end(),
                     [](auto e) { return e > 0; });
}

template <typename Iter> inline bool try_advance(Iter end, Iter &dst) {
  if (std::next(dst) != end) {
    std::advance(dst, 1);
    return true;
  }
  return false;
}

/**
@brief: two pointers

The problem gurantees that given sequence has at least one
point which is colored with `i` where 0 <= i < k

*/
inline size_t solution(Vec &&ls, size_t k) {
  const auto BEGIN = ls.begin();
  const auto END = ls.end();
  for (auto &e : ls) {
    e -= 1; // normalize
  }
  // initial registration of sequences,
  // b_inner starts in range [0, 0), which is empty and
  // b_outer starts in range [0, n), which has all
  auto b_outer = Vec(k);
  auto b_inner = Vec(k);
  for (auto cr e : ls) {
    b_outer[e] += 1;
  }

  size_t ret = INV;
  auto lo = BEGIN;
  auto hi = lo;

  while (lo != END && hi != END) {
    if (is_rainbow(b_inner)) {
      if (is_rainbow(b_outer)) {
        // @@@@@@ DOUBLE RAINBOW @@@@@@
        auto len = std::distance(lo, hi);
        ret = std::min(ret, size_t(len));
        // Because much shorter answer might exists, keep going through
        // with advancing `lo` iterator
        b_inner[*lo] -= 1;
        b_outer[*lo] += 1;
        if (!try_advance(END, lo)) {
          goto EARLY_RETURN;
        }
      } else {
        // feed b_outer with advancing `lo` iterator
        b_inner[*lo] -= 1;
        b_outer[*lo] += 1;
        if (!try_advance(END, lo)) {
          goto EARLY_RETURN;
        }
      }
    } else {
      // no rainbow found, feed `b_inner` with advancing `hi` iterator
      b_inner[*hi] += 1;
      b_outer[*hi] -= 1;
      if (!try_advance(END, hi)) {
        goto EARLY_RETURN;
      }
    }
  }

EARLY_RETURN:

  if (ret == INV) {
    // no double rainbow found
    return 0;
  }
  return ret;
}


#include <ios>
#include <iostream>

using namespace std;

int main(void) {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n;
  size_t k;
  cin >> n >> k;

  auto ls = Vec(n);
  for (size_t i = 0; i < n; ++i) {
    cin >> ls[i];
  }

  auto answer = solution(std::move(ls), k);

  cout << answer << "\n";

  return 0;
}