競技プログラミング用の C++ ライブラリ
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A"
// Range を愚直に作った std::vector (Python の range と同じ列) とランダムに比較する
// 問題の入力は使わず、すべて一致したら Hello World を出力する
#include <algorithm>
#include <iostream>
#include <iterator>
#include <random>
#include <string>
#include <vector>
#include "../../src/base/range.hpp"
using ll = long long;
// Python の range(start, stop, step) と同じ列
std::vector<ll> naive_range(ll start, ll stop, ll step) {
std::vector<ll> v;
if (step > 0) {
for (ll x = start; x < stop; x += step) v.push_back(x);
} else {
for (ll x = start; x > stop; x += step) v.push_back(x);
}
return v;
}
std::vector<ll> by_iteration(const Range& r) {
std::vector<ll> v;
for (ll x : r) v.push_back(x);
return v;
}
// コンパイル時にも使える
static_assert(Range(0, 10, 3).size() == 4);
static_assert(Range(10, 0, -3).sum() == 22);
static_assert(Range(5).max() == 4);
int main() {
std::mt19937_64 rng(314);
auto rnd = [&](ll lo, ll hi) { return lo + (ll)(rng() % (unsigned long long)(hi - lo + 1)); };
bool ok = true;
auto check = [&](bool cond, const char* what) {
if (!cond) {
if (ok) std::cerr << "failed: " << what << std::endl;
ok = false;
}
};
// コンストラクタ
check(by_iteration(Range(5)) == naive_range(0, 5, 1), "Range(stop)");
check(by_iteration(Range(-3)).empty(), "Range(negative stop)");
check(by_iteration(Range(2, 7)) == naive_range(2, 7, 1), "Range(start, stop)");
check(Range().empty() && Range().size() == 0 && by_iteration(Range()).empty(), "Range()");
{
Range a(1, 20, 4);
Range b(a); // コピー
check(by_iteration(b) == naive_range(1, 20, 4), "copy");
}
for (int rep = 0; rep < 20000 && ok; rep++) {
ll start = rnd(-20, 20), stop = rnd(-20, 20), step = rnd(1, 7) * (rng() % 2 ? 1 : -1);
Range r(start, stop, step);
std::vector<ll> v = naive_range(start, stop, step);
int n = v.size();
check(r.start == start && r.stop == stop && r.step == step, "members");
check(by_iteration(r) == v, "iteration");
check(r.to_vector() == v, "to_vector");
check(std::vector<ll>(r.begin(), r.end()) == v, "iterator range constructor");
check(r.size() == (size_t)n, "size");
check(r.empty() == v.empty(), "empty");
check(r.end() - r.begin() == n, "end - begin");
for (int i = 0; i < n; i++) {
check(r.at(i) == v[i] && r[i] == v[i], "at / []");
}
// count, contains, index, find
for (ll x = -30; x <= 30; x++) {
int c = std::count(v.begin(), v.end(), x);
check(r.count(x) == c, "count");
check(r.contains(x) == (c > 0), "contains");
if (c > 0) {
int idx = std::find(v.begin(), v.end(), x) - v.begin();
check(r.index(x) == (size_t)idx, "index");
check(*r.find(x) == x && r.find(x) - r.begin() == idx, "find (found)");
} else {
check(r.find(x) == r.end(), "find (not found)");
}
}
// lower_bound, upper_bound (step > 0 のときだけ使える)
if (step > 0) {
for (ll x = -30; x <= 30; x++) {
check(r.lower_bound(x) - r.begin() == std::lower_bound(v.begin(), v.end(), x) - v.begin(), "lower_bound");
check(r.upper_bound(x) - r.begin() == std::upper_bound(v.begin(), v.end(), x) - v.begin(), "upper_bound");
}
}
// sum, min, max
ll sum = 0;
for (ll x : v) sum += x;
check(r.sum() == sum, "sum");
if (n > 0) {
check(r.min() == *std::min_element(v.begin(), v.end()), "min");
check(r.max() == *std::max_element(v.begin(), v.end()), "max");
}
// reversed, sorted
std::vector<ll> rv(v.rbegin(), v.rend()), sv = v;
std::sort(sv.begin(), sv.end());
check(by_iteration(r.reversed()) == rv && r.reversed().size() == (size_t)n, "reversed");
check(by_iteration(r.sorted()) == sv && r.sorted().size() == (size_t)n, "sorted");
// clipped: 値が [l, r] の要素だけを順番を保って残す
{
ll l = rnd(-25, 25), rr = rnd(-25, 25);
std::vector<ll> expect;
if (l <= rr) {
for (ll x : v)
if (l <= x && x <= rr) expect.push_back(x);
}
Range c = r.clipped(l, rr);
check(by_iteration(c) == expect && c.size() == expect.size(), "clipped");
}
// slice: インデックスを Range で指定する (範囲外のインデックスは無視)
{
ll s2 = rnd(-25, 25), t2 = rnd(-25, 25), st2 = rnd(1, 5) * (rng() % 2 ? 1 : -1);
Range idx(s2, t2, st2);
std::vector<ll> expect;
for (ll i : naive_range(s2, t2, st2))
if (0 <= i && i < n) expect.push_back(v[i]);
Range s = r.slice(idx);
check(by_iteration(s) == expect && s.size() == expect.size(), "slice");
}
// ==, != は列として等しいか
{
ll start2 = rng() % 4 == 0 ? start : rnd(-20, 20);
ll stop2 = rng() % 2 == 0 ? stop + rnd(-3, 3) : rnd(-20, 20);
ll step2 = rng() % 2 == 0 ? step : rnd(1, 7) * (rng() % 2 ? 1 : -1);
Range r2(start2, stop2, step2);
bool same = v == naive_range(start2, stop2, step2);
check((r == r2) == same && (r != r2) == !same, "== / !=");
}
// イテレータの各演算
if (n > 0) {
int i = rnd(0, n - 1), j = rnd(0, n - 1);
auto it = r.begin() + i;
check(*it == v[i] && it.base() == v[i], "begin + i");
check(*(i + r.begin()) == v[i], "i + begin");
check(*(r.end() - (n - i)) == v[i], "end - k");
check((r.begin() + j) - it == j - i, "iterator difference");
auto it2 = it; // コピーコンストラクタ
check(it2 == it && !(it2 != it), "copy / ==");
it2 = r.begin(); // 同じ Range のイテレータの代入
check(*it2 == v[0], "operator=");
auto a = it;
auto b = a++;
check(*b == v[i] && a - b == 1, "post ++");
auto c = ++b;
check(c == a && *c == *a, "pre ++");
auto d = a--;
check(d - a == 1 && *a == v[i], "post --");
--d;
check(d == a, "pre --");
auto e = it;
e += j - i;
check(*(e) == v[j] || j == n, "+=");
e -= j - i;
check(e == it, "-=");
check(it != r.end(), "!= end");
}
check(r.begin() + n == r.end(), "begin + size == end");
}
// product_xor (負を含まない列)
for (int rep = 0; rep < 5000 && ok; rep++) {
ll start, stop, step;
if (rep % 2 == 0) {
start = rnd(0, 100), stop = rnd(0, 100), step = rnd(1, 9) * (rng() % 2 ? 1 : -1);
if (step < 0 && stop < -1) stop = -1;
} else {
// 大きい値 (要素数は少なめ)
start = rnd(0, 1000000000000LL), step = rnd(1, 1000000000LL) * (rng() % 2 ? 1 : -1);
stop = start + step * rnd(0, 300);
if (stop < -1) stop = -1;
}
Range r(start, stop, step);
ll x = 0;
for (ll y : naive_range(start, stop, step)) x ^= y;
check(r.product_xor() == x, "product_xor");
}
// 文字列化
{
Range r(-3, 10, 2);
check(Range::type_str() == "Range", "type_str");
check(r.initializer_str() == "{-3, 10, 2}", "initializer_str");
check(r.repr() == "Range(-3, 10, 2)", "repr");
}
if (ok) std::cout << "Hello World" << std::endl;
}#line 1 "test/unittest/range.test.cpp"
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A"
// Range を愚直に作った std::vector (Python の range と同じ列) とランダムに比較する
// 問題の入力は使わず、すべて一致したら Hello World を出力する
#include <algorithm>
#include <iostream>
#include <iterator>
#include <random>
#include <string>
#include <vector>
#line 2 "src/base/range.hpp"
/**
* @file range.hpp
* @brief Python の range のような整数列
*/
#include <cassert>
#include <cstddef>
#line 12 "src/base/range.hpp"
#include <type_traits>
#include <utility>
#line 15 "src/base/range.hpp"
struct Range {
public:
using value_type = long long;
using const_reference = const value_type&;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
const value_type start;
const value_type stop;
const value_type step;
private:
const value_type norm_stop;
constexpr static value_type normalize(value_type _start, value_type _stop, value_type _step) {
assert(_step != 0);
if (_step > 0) {
if (_start >= _stop) {
return _start;
} else {
return _start + (_stop - _start + _step - 1) / _step * _step;
}
} else {
if (_start <= _stop) {
return _start;
} else {
return _start - (_start - _stop - _step - 1) / _step * _step;
}
}
}
constexpr Range(value_type _start, value_type _stop, value_type _step, value_type _norm_stop)
: start(_start), stop(_stop), step(_step), norm_stop(_norm_stop) {
}
public:
/**
* @brief start から stop の手前まで step ずつ進む整数列
* @pre step != 0
*/
constexpr Range(value_type _start, value_type _stop, value_type _step)
: start(_start), stop(_stop), step(_step), norm_stop(normalize(_start, _stop, _step)) {
}
constexpr Range(value_type _start, value_type _stop)
: start(_start), stop(_stop), step(1), norm_stop(normalize(_start, _stop, 1)) {}
constexpr Range(value_type _stop)
: start(0), stop(_stop), step(1), norm_stop(normalize(0, _stop, 1)) {}
constexpr Range()
: start(0), stop(0), step(1), norm_stop(0) {
}
constexpr Range(const Range& o) = default;
Range& operator=(const Range& o) = delete;
struct const_iterator {
public:
using difference_type = Range::difference_type;
using value_type = Range::value_type;
using pointer = const Range::value_type*;
using reference = const Range::value_type&;
using iterator_category = std::random_access_iterator_tag;
private:
const Range& range;
value_type value;
constexpr bool same_range(const const_iterator& o) const noexcept {
return range.start == o.range.start and range.stop == o.range.stop and range.step == o.range.step;
}
public:
constexpr const_iterator(const Range& _range, value_type _value) noexcept
: range(_range), value(_value) {}
constexpr const_iterator(const const_iterator& o) noexcept
: range(o.range), value(o.value) {}
constexpr reference base() const noexcept {
return value;
}
constexpr const_iterator& operator=(const const_iterator& o) {
assert(same_range(o));
value = o.value;
return *this;
};
constexpr const_iterator& operator++() noexcept {
value += range.step;
return *this;
}
constexpr const_iterator operator++(int) noexcept {
const_iterator ret(*this);
value += range.step;
return ret;
}
constexpr const_iterator& operator+=(difference_type _n) noexcept {
value += _n * range.step;
return *this;
}
constexpr friend const_iterator operator+(const const_iterator& i, difference_type _n) noexcept {
const_iterator ret(i);
ret += _n;
return ret;
}
constexpr friend const_iterator operator+(difference_type _n, const const_iterator& i) noexcept {
const_iterator ret(i);
ret += _n;
return ret;
}
constexpr const_iterator& operator--() noexcept {
value -= range.step;
return *this;
}
constexpr const_iterator operator--(int) noexcept {
const_iterator ret(*this);
value -= range.step;
return ret;
}
constexpr const_iterator& operator-=(difference_type _n) noexcept {
value -= _n * range.step;
return *this;
}
constexpr friend const_iterator operator-(const const_iterator& i, difference_type _n) noexcept {
const_iterator ret(i);
ret -= _n;
return ret;
}
constexpr reference operator*() const noexcept {
return value;
}
constexpr friend bool operator!=(const const_iterator& a, const const_iterator& b) noexcept {
return !a.same_range(b) or a.value != b.value;
}
constexpr friend bool operator==(const const_iterator& a, const const_iterator& b) noexcept {
return !(a != b);
}
constexpr friend difference_type operator-(const const_iterator& a, const const_iterator& b) {
assert(a.same_range(b));
if (a.range.step > 0) {
return (a.value - b.value) / a.range.step;
} else {
return (b.value - a.value) / (-a.range.step);
}
}
};
constexpr const_iterator begin() const noexcept {
return {*this, start};
}
constexpr const_iterator end() const noexcept {
return {*this, norm_stop};
}
/**
* @brief x の個数 (0 か 1)
*/
constexpr difference_type count(value_type x) const noexcept {
if (step > 0) {
if (start <= x and x < stop) {
if ((x - start) % step == 0) {
return 1;
}
}
} else {
if (stop < x and x <= start) {
if ((start - x) % (-step) == 0) {
return 1;
}
}
}
return 0;
}
/**
* @brief x が含まれるか
*/
constexpr bool contains(value_type x) const noexcept {
return count(x) != 0;
}
/**
* @brief x のインデックス
* x が含まれないとエラー
*/
constexpr size_type index(value_type x) const {
assert(contains(x));
return (x - start) / step;
}
/**
* @brief 要素が x のイテレータ
* x が含まれないと end() を返す
*/
constexpr const_iterator find(value_type x) const noexcept {
if (contains(x)) {
return {*this, x};
} else {
return {*this, norm_stop};
}
}
/**
* @brief 要素が x 以上の最小のイテレータ
* step > 0 じゃないとエラー
*/
constexpr const_iterator lower_bound(value_type x) const {
assert(step > 0);
if (norm_stop <= x) {
return end();
} else if (x < start) {
return begin();
} else {
return {*this, start + (x - start + step - 1) / step * step};
}
}
/**
* @brief 要素が x より大きい最小のイテレータ
* step > 0 じゃないとエラー
*/
constexpr const_iterator upper_bound(value_type x) const {
assert(step > 0);
if (norm_stop <= x) {
return end();
} else if (x < start) {
return begin();
} else {
return {*this, start + (x - start + step) / step * step};
}
}
/**
* @brief コンテナの要素数
*/
constexpr size_type size() const noexcept {
if (step > 0) {
return (norm_stop - start) / step;
} else {
return (start - norm_stop) / (-step);
}
}
constexpr value_type at(size_type i) const {
assert(i < size());
return start + i * step;
}
constexpr value_type operator[](size_type i) const {
return at(i);
}
constexpr bool empty() const noexcept {
return start == norm_stop;
}
constexpr value_type sum() const noexcept {
return static_cast<Range::value_type>(size()) * (norm_stop - step + start) / 2;
}
/**
* @brief 最小値
* 空だとエラー
*/
constexpr value_type min() const {
assert(not empty());
if (step > 0) {
return start;
} else {
return norm_stop - step;
}
}
/**
* @brief 最大値
* 空だとエラー
*/
constexpr value_type max() const {
assert(not empty());
if (step > 0) {
return norm_stop - step;
} else {
return start;
}
}
/**
* @brief 総 xor
* 負を含むとエラー
*/
constexpr value_type product_xor() const noexcept {
if (empty()) return 0;
assert(min() >= 0);
Range sorted_range(sorted());
value_type res = 0;
std::make_unsigned_t<value_type> t = 1;
while (t <= static_cast<std::make_unsigned_t<value_type>>(max())) {
std::make_unsigned_t<value_type> tmp = 0, n = size(), m = t, a = sorted_range.step, b = sorted_range.start;
while (true) {
if (a >= m) {
tmp += n * (n - 1) / 2 * (a / m);
a %= m;
}
if (b >= m) {
tmp += n * (b / m);
b %= m;
}
std::make_unsigned_t<value_type> y_max = a * n + b;
if (y_max < m) break;
n = y_max / m;
b = y_max % m;
std::swap(m, a);
}
if (tmp % 2 == 1) {
res += t;
}
t <<= 1;
}
return res;
}
/**
* @brief 逆順にしたもの
*/
constexpr Range reversed() const noexcept {
return {norm_stop - step, start - step, -step, start - step};
}
/**
* @brief step > 0 だとそのまま step < 0 だと逆順にしたもの
*/
constexpr Range sorted() const noexcept {
if (step > 0) {
return {start, norm_stop, step, norm_stop};
} else {
return {norm_stop - step, start - step, -step, start - step};
}
}
/**
* @brief 要素が [l,r] である範囲を返す
*/
constexpr Range clipped(value_type l, value_type r) const {
if (l > r) return {};
if (step > 0) {
value_type _start = [&] {
if (norm_stop <= l) {
return norm_stop;
} else if (l < start) {
return start;
} else {
return start + (l - start + step - 1) / step * step;
}
}();
value_type _stop = [&] {
if (norm_stop <= r) {
return norm_stop;
} else if (r < start) {
return start;
} else {
return start + (r - start + step) / step * step;
}
}();
return {_start, _stop, step, _stop};
} else {
value_type _start = [&] {
if (start - step <= r) {
return start;
} else if (r < norm_stop - step) {
return norm_stop;
} else {
return norm_stop + (r - norm_stop) / step * step;
}
}();
value_type _stop = [&] {
if (start - step <= l) {
return start;
} else if (l < norm_stop - step) {
return norm_stop;
} else {
return norm_stop + (l - norm_stop - 1) / step * step;
}
}();
return {_start, _stop, step, _stop};
}
}
/**
* @brief 要素を Range で指定したコンテナ
*/
constexpr Range slice(const Range& r) const {
if (r.empty()) return {};
if (r.max() < 0) return {};
if (r.min() >= static_cast<Range::value_type>(size())) return {};
Range trimmed_range(r.clipped(0, static_cast<Range::value_type>(size()) - 1));
if (trimmed_range.empty()) return {};
value_type _step = step * trimmed_range.step;
value_type _start = at(trimmed_range.start);
value_type _stop = _start + _step * static_cast<Range::value_type>(trimmed_range.size());
return {_start, _stop, _step, _stop};
}
static std::string type_str() {
return "Range";
}
std::string initializer_str() const {
return "{" + std::to_string(start) + ", " + std::to_string(stop) + ", " + std::to_string(step) + "}";
}
std::string repr() const {
return "Range(" + std::to_string(start) + ", " + std::to_string(stop) + ", " + std::to_string(step) + ")";
}
std::vector<value_type> to_vector() const {
std::vector<value_type> ret;
ret.reserve(size());
if (step > 0) {
for (value_type x = start; x < stop; x += step) {
ret.push_back(x);
}
} else {
for (value_type x = start; x > stop; x += step) {
ret.push_back(x);
}
}
return ret;
}
constexpr friend bool operator==(const Range& a, const Range& b) noexcept {
if (a.empty() and b.empty()) return true;
if (a.size() != b.size()) return false;
if (a.start != b.start) return false;
if (a.size() == 1) return true;
if (a.step != b.step) return false;
return true;
}
constexpr friend bool operator!=(const Range& a, const Range& b) noexcept {
return !(a == b);
}
};
#line 14 "test/unittest/range.test.cpp"
using ll = long long;
// Python の range(start, stop, step) と同じ列
std::vector<ll> naive_range(ll start, ll stop, ll step) {
std::vector<ll> v;
if (step > 0) {
for (ll x = start; x < stop; x += step) v.push_back(x);
} else {
for (ll x = start; x > stop; x += step) v.push_back(x);
}
return v;
}
std::vector<ll> by_iteration(const Range& r) {
std::vector<ll> v;
for (ll x : r) v.push_back(x);
return v;
}
// コンパイル時にも使える
static_assert(Range(0, 10, 3).size() == 4);
static_assert(Range(10, 0, -3).sum() == 22);
static_assert(Range(5).max() == 4);
int main() {
std::mt19937_64 rng(314);
auto rnd = [&](ll lo, ll hi) { return lo + (ll)(rng() % (unsigned long long)(hi - lo + 1)); };
bool ok = true;
auto check = [&](bool cond, const char* what) {
if (!cond) {
if (ok) std::cerr << "failed: " << what << std::endl;
ok = false;
}
};
// コンストラクタ
check(by_iteration(Range(5)) == naive_range(0, 5, 1), "Range(stop)");
check(by_iteration(Range(-3)).empty(), "Range(negative stop)");
check(by_iteration(Range(2, 7)) == naive_range(2, 7, 1), "Range(start, stop)");
check(Range().empty() && Range().size() == 0 && by_iteration(Range()).empty(), "Range()");
{
Range a(1, 20, 4);
Range b(a); // コピー
check(by_iteration(b) == naive_range(1, 20, 4), "copy");
}
for (int rep = 0; rep < 20000 && ok; rep++) {
ll start = rnd(-20, 20), stop = rnd(-20, 20), step = rnd(1, 7) * (rng() % 2 ? 1 : -1);
Range r(start, stop, step);
std::vector<ll> v = naive_range(start, stop, step);
int n = v.size();
check(r.start == start && r.stop == stop && r.step == step, "members");
check(by_iteration(r) == v, "iteration");
check(r.to_vector() == v, "to_vector");
check(std::vector<ll>(r.begin(), r.end()) == v, "iterator range constructor");
check(r.size() == (size_t)n, "size");
check(r.empty() == v.empty(), "empty");
check(r.end() - r.begin() == n, "end - begin");
for (int i = 0; i < n; i++) {
check(r.at(i) == v[i] && r[i] == v[i], "at / []");
}
// count, contains, index, find
for (ll x = -30; x <= 30; x++) {
int c = std::count(v.begin(), v.end(), x);
check(r.count(x) == c, "count");
check(r.contains(x) == (c > 0), "contains");
if (c > 0) {
int idx = std::find(v.begin(), v.end(), x) - v.begin();
check(r.index(x) == (size_t)idx, "index");
check(*r.find(x) == x && r.find(x) - r.begin() == idx, "find (found)");
} else {
check(r.find(x) == r.end(), "find (not found)");
}
}
// lower_bound, upper_bound (step > 0 のときだけ使える)
if (step > 0) {
for (ll x = -30; x <= 30; x++) {
check(r.lower_bound(x) - r.begin() == std::lower_bound(v.begin(), v.end(), x) - v.begin(), "lower_bound");
check(r.upper_bound(x) - r.begin() == std::upper_bound(v.begin(), v.end(), x) - v.begin(), "upper_bound");
}
}
// sum, min, max
ll sum = 0;
for (ll x : v) sum += x;
check(r.sum() == sum, "sum");
if (n > 0) {
check(r.min() == *std::min_element(v.begin(), v.end()), "min");
check(r.max() == *std::max_element(v.begin(), v.end()), "max");
}
// reversed, sorted
std::vector<ll> rv(v.rbegin(), v.rend()), sv = v;
std::sort(sv.begin(), sv.end());
check(by_iteration(r.reversed()) == rv && r.reversed().size() == (size_t)n, "reversed");
check(by_iteration(r.sorted()) == sv && r.sorted().size() == (size_t)n, "sorted");
// clipped: 値が [l, r] の要素だけを順番を保って残す
{
ll l = rnd(-25, 25), rr = rnd(-25, 25);
std::vector<ll> expect;
if (l <= rr) {
for (ll x : v)
if (l <= x && x <= rr) expect.push_back(x);
}
Range c = r.clipped(l, rr);
check(by_iteration(c) == expect && c.size() == expect.size(), "clipped");
}
// slice: インデックスを Range で指定する (範囲外のインデックスは無視)
{
ll s2 = rnd(-25, 25), t2 = rnd(-25, 25), st2 = rnd(1, 5) * (rng() % 2 ? 1 : -1);
Range idx(s2, t2, st2);
std::vector<ll> expect;
for (ll i : naive_range(s2, t2, st2))
if (0 <= i && i < n) expect.push_back(v[i]);
Range s = r.slice(idx);
check(by_iteration(s) == expect && s.size() == expect.size(), "slice");
}
// ==, != は列として等しいか
{
ll start2 = rng() % 4 == 0 ? start : rnd(-20, 20);
ll stop2 = rng() % 2 == 0 ? stop + rnd(-3, 3) : rnd(-20, 20);
ll step2 = rng() % 2 == 0 ? step : rnd(1, 7) * (rng() % 2 ? 1 : -1);
Range r2(start2, stop2, step2);
bool same = v == naive_range(start2, stop2, step2);
check((r == r2) == same && (r != r2) == !same, "== / !=");
}
// イテレータの各演算
if (n > 0) {
int i = rnd(0, n - 1), j = rnd(0, n - 1);
auto it = r.begin() + i;
check(*it == v[i] && it.base() == v[i], "begin + i");
check(*(i + r.begin()) == v[i], "i + begin");
check(*(r.end() - (n - i)) == v[i], "end - k");
check((r.begin() + j) - it == j - i, "iterator difference");
auto it2 = it; // コピーコンストラクタ
check(it2 == it && !(it2 != it), "copy / ==");
it2 = r.begin(); // 同じ Range のイテレータの代入
check(*it2 == v[0], "operator=");
auto a = it;
auto b = a++;
check(*b == v[i] && a - b == 1, "post ++");
auto c = ++b;
check(c == a && *c == *a, "pre ++");
auto d = a--;
check(d - a == 1 && *a == v[i], "post --");
--d;
check(d == a, "pre --");
auto e = it;
e += j - i;
check(*(e) == v[j] || j == n, "+=");
e -= j - i;
check(e == it, "-=");
check(it != r.end(), "!= end");
}
check(r.begin() + n == r.end(), "begin + size == end");
}
// product_xor (負を含まない列)
for (int rep = 0; rep < 5000 && ok; rep++) {
ll start, stop, step;
if (rep % 2 == 0) {
start = rnd(0, 100), stop = rnd(0, 100), step = rnd(1, 9) * (rng() % 2 ? 1 : -1);
if (step < 0 && stop < -1) stop = -1;
} else {
// 大きい値 (要素数は少なめ)
start = rnd(0, 1000000000000LL), step = rnd(1, 1000000000LL) * (rng() % 2 ? 1 : -1);
stop = start + step * rnd(0, 300);
if (stop < -1) stop = -1;
}
Range r(start, stop, step);
ll x = 0;
for (ll y : naive_range(start, stop, step)) x ^= y;
check(r.product_xor() == x, "product_xor");
}
// 文字列化
{
Range r(-3, 10, 2);
check(Range::type_str() == "Range", "type_str");
check(r.initializer_str() == "{-3, 10, 2}", "initializer_str");
check(r.repr() == "Range(-3, 10, 2)", "repr");
}
if (ok) std::cout << "Hello World" << std::endl;
}