proconlib

This documentation is automatically generated by competitive-verifier/competitive-verifier

View the Project on GitHub anqooqie/proconlib

:warning: Enumerate all matchings (tools/next_matching.hpp)

template <typename RandomAccessIterator>
bool next_matching(RandomAccessIterator begin, RandomAccessIterator end);

It enumerates all the ways to divide $\{0, 1, \ldots, N - 1\}$ into $\left\lfloor \frac{N}{2} \right\rfloor$ unordered pairs and at most one remainder. It can be used as follows.

std::vector<int> a(N);
std::iota(a.begin(), a.end(), 0);
do {
  // a[0] and a[1] are a pair, a[2] and a[3] are a pair, and so on.
} while (tools::next_matching(a.begin(), a.end()));

It returns true if the next way exists, false otherwise.

Constraints

Time Complexity

License

Author

Verified with

Code

#ifndef TOOLS_NEXT_MATCHING_HPP
#define TOOLS_NEXT_MATCHING_HPP

#include <iterator>
#include <cassert>
#include <algorithm>

namespace tools {
  template <typename RandomAccessIterator>
  bool next_matching(RandomAccessIterator begin, RandomAccessIterator end) {
    const auto N = ::std::distance(begin, end);
    // assert(::tools::mex(begin, end) == N);
    if (N <= 2) return false;

    auto l = (N - 2) / 2 * 2;
    for (; l > 0 && begin[l - 1] > begin[l + 1]; l -= 2);
    ::std::sort(::std::next(begin, l), ::std::prev(end, N % 2));

    if (l == 0) {
      if (N % 2 == 0) return false;
      if (begin[N - 1] == 0) {
        ::std::rotate(begin, ::std::prev(end), end);
        return false;
      }
      ::std::iter_swap(::std::next(begin, begin[N - 1] - 1), ::std::prev(end));
      return true;
    }

    ::std::iter_swap(::std::next(begin, l - 1), ::std::upper_bound(::std::next(begin, l), ::std::prev(end, N % 2), begin[l - 1]));
    return true;
  }
}

#endif
#line 1 "tools/next_matching.hpp"



#include <iterator>
#include <cassert>
#include <algorithm>

namespace tools {
  template <typename RandomAccessIterator>
  bool next_matching(RandomAccessIterator begin, RandomAccessIterator end) {
    const auto N = ::std::distance(begin, end);
    // assert(::tools::mex(begin, end) == N);
    if (N <= 2) return false;

    auto l = (N - 2) / 2 * 2;
    for (; l > 0 && begin[l - 1] > begin[l + 1]; l -= 2);
    ::std::sort(::std::next(begin, l), ::std::prev(end, N % 2));

    if (l == 0) {
      if (N % 2 == 0) return false;
      if (begin[N - 1] == 0) {
        ::std::rotate(begin, ::std::prev(end), end);
        return false;
      }
      ::std::iter_swap(::std::next(begin, begin[N - 1] - 1), ::std::prev(end));
      return true;
    }

    ::std::iter_swap(::std::next(begin, l - 1), ::std::upper_bound(::std::next(begin, l), ::std::prev(end, N % 2), begin[l - 1]));
    return true;
  }
}


Back to top page