shogo-library

競技プログラミング用の C++ ライブラリ

View the Project on GitHub shogo314/shogo-library

:heavy_check_mark: test/unittest/container-func.test.cpp

Depends on

Code

#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A"

// container_func.hpp の関数を愚直な実装とランダムに比較する
// 問題の入力は使わず、すべて一致したら Hello World を出力する

#include <algorithm>
#include <functional>
#include <iostream>
#include <numeric>
#include <random>
#include <set>
#include <string>
#include <vector>

#include "../../src/base/container_func.hpp"

bool ok = true;

void check(bool cond, const char* what) {
    if (!cond) {
        if (ok) std::cerr << "failed: " << what << std::endl;
        ok = false;
    }
}

int main() {
    std::mt19937_64 rng(314);
    auto rand_vec = [&](int n, long long lo, long long hi) {
        std::vector<long long> v(n);
        for (auto& x : v) x = lo + (long long)(rng() % (unsigned long long)(hi - lo + 1));
        return v;
    };

    for (int rep = 0; rep < 2000 && ok; rep++) {
        int n = rng() % 10 + 1;
        std::vector<long long> v = rand_vec(n, -5, 5);

        // sorted / sort (比較関数つき)
        {
            std::vector<long long> expect = v;
            std::sort(expect.begin(), expect.end(), std::greater<long long>());
            check(sorted(v, std::greater<long long>()) == expect, "sorted(c, f)");
            std::vector<long long> w = v;
            sort(w, std::greater<long long>());
            check(w == expect, "sort(c, f)");
        }

        // set / multiset に対する max / min (ソート済みのコンテナは先頭と末尾)
        {
            std::set<long long> s(v.begin(), v.end());
            std::multiset<long long> ms(v.begin(), v.end());
            long long mx = *std::max_element(v.begin(), v.end());
            long long mn = *std::min_element(v.begin(), v.end());
            check(max(s) == mx && min(s) == mn, "max/min(set)");
            check(max(ms) == mx && min(ms) == mn, "max/min(multiset)");
            check(max(v) == mx && min(v) == mn, "max/min(vector)");
        }

        // product / product_xor
        {
            std::vector<long long> small = rand_vec(n, -3, 3);
            long long p = 1, x = 0;
            for (long long a : small) p *= a, x ^= a;
            check(product(small) == p, "product(c)");
            check(product_xor(small) == x, "product_xor(c)");
            std::vector<long long> nonneg = rand_vec(n, 0, 1000000);
            long long y = 0;
            for (long long a : nonneg) y ^= a;
            check(product_xor(nonneg) == y, "product_xor(c) large");
        }

        // maximum_subarray (空の部分列を許す版): 全区間の和の最大値と init の大きい方
        {
            long long init = (long long)(rng() % 7) - 3;
            long long best = init;
            for (int l = 0; l < n; l++) {
                long long s = init;
                for (int r = l; r < n; r++) {
                    s += v[r];
                    best = std::max(best, s);
                }
            }
            check(maximum_subarray(v, init) == best, "maximum_subarray(c, init)");
            // 空でない版も合わせて確かめる
            long long best_nonempty = v[0];
            for (int l = 0; l < n; l++) {
                long long s = 0;
                for (int r = l; r < n; r++) {
                    s += v[r];
                    best_nonempty = std::max(best_nonempty, s);
                }
            }
            check(maximum_subarray(v) == best_nonempty, "maximum_subarray(c)");
        }

        // median: 偶数個なら中央 2 つの平均 (整数型は 0 方向に切り捨て)
        {
            std::vector<long long> w = v;
            std::sort(w.begin(), w.end());
            long long expect = n % 2 ? w[n / 2] : (w[n / 2 - 1] + w[n / 2]) / 2;
            check(median(v) == expect, "median(vector<long long>)");
            std::vector<double> d(v.begin(), v.end());
            std::vector<double> dw = d;
            std::sort(dw.begin(), dw.end());
            double dexp = n % 2 ? dw[n / 2] : (dw[n / 2 - 1] + dw[n / 2]) / 2;
            check(median(d) == dexp, "median(vector<double>)");
        }

        // index: 最初に現れる位置、なければ size
        {
            long long x = (long long)(rng() % 13) - 6;
            long long expect = std::find(v.begin(), v.end(), x) - v.begin();
            check(index(v, x) == expect, "index(c, x)");
        }

        // mex: 含まれない最小の非負整数
        {
            std::vector<int> w(n);
            for (auto& a : w) a = (int)(rng() % 8) - 2;
            int expect = 0;
            while (std::find(w.begin(), w.end(), expect) != w.end()) expect++;
            check(mex(w) == expect, "mex(c)");
        }

        // count / find / lower_bound / upper_bound (set はメンバ関数、vector は std:: のアルゴリズム)
        {
            long long x = (long long)(rng() % 13) - 6;
            std::multiset<long long> ms(v.begin(), v.end());
            std::vector<long long> w = v;
            std::sort(w.begin(), w.end());
            check(count(ms, x) == (std::size_t)std::count(v.begin(), v.end(), x), "count(multiset, x)");
            check(count(v, x) == std::count(v.begin(), v.end(), x), "count(vector, x)");
            check((find(ms, x) != ms.end()) == (std::find(v.begin(), v.end(), x) != v.end()), "find(multiset, x)");
            check(find(v, x) == std::find(v.begin(), v.end(), x), "find(vector, x)");
            check(lower_bound(ms, x) == ms.lower_bound(x) && upper_bound(ms, x) == ms.upper_bound(x), "lower/upper_bound(multiset, x)");
            check(lower_bound(w, x) == std::lower_bound(w.begin(), w.end(), x), "lower_bound(vector, x)");
            check(upper_bound(w, x) == std::upper_bound(w.begin(), w.end(), x), "upper_bound(vector, x)");
            check(contains(v, x) == (std::find(v.begin(), v.end(), x) != v.end()), "contains(vector, x)");
        }
    }

    // 初期化子リスト版
    check(max({3, -1, 7, 2}) == 7, "max(initializer_list)");
    check(min({3, -1, 7, 2}) == -1, "min(initializer_list)");
    check(sum({3, -1, 7, 2}) == 11, "sum(initializer_list)");
    check(product({3, -1, 7, 2}) == -42, "product(initializer_list)");
    check(product_xor({3, 5, 6}) == 0, "product_xor(initializer_list)");
    check(max({5}) == 5 && min({5}) == 5, "max/min(initializer_list) 1 要素");

    // 境界: 1 要素、空
    check(median(std::vector<int>{4}) == 4, "median 1 要素");
    check(median(std::vector<int>{1, 4}) == 2, "median 2 要素");
    check(mex(std::vector<int>{}) == 0, "mex 空");
    check(mex(std::vector<int>{0, 1, 2}) == 3, "mex 0..n-1 をすべて含む");
    check(maximum_subarray(std::vector<int>{}, 0) == 0, "maximum_subarray 空");
    check(maximum_subarray(std::vector<int>{-5, -2, -9}) == -2, "maximum_subarray すべて負");
    check(maximum_subarray(std::vector<int>{-5, -2, -9}, 0) == 0, "maximum_subarray すべて負、空を許す");
    check(product(std::vector<int>{}) == 1 && product_xor(std::vector<int>{}) == 0, "product 空");
    check(index(std::vector<int>{}, 3) == 0, "index 空");
    check(sorted(std::string("bca"), std::greater<char>()) == "cba", "sorted(string, f)");

    if (ok) std::cout << "Hello World" << std::endl;
}
#line 1 "test/unittest/container-func.test.cpp"
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A"

// container_func.hpp の関数を愚直な実装とランダムに比較する
// 問題の入力は使わず、すべて一致したら Hello World を出力する

#include <algorithm>
#include <functional>
#include <iostream>
#include <numeric>
#include <random>
#include <set>
#include <string>
#include <vector>

#line 2 "src/base/container_func.hpp"

/**
 * @file container_func.hpp
 * @brief コンテナに対する関数 (sorted, max, sum など)
 */

#line 9 "src/base/container_func.hpp"
#include <cassert>
#line 11 "src/base/container_func.hpp"
#include <initializer_list>
#include <iterator>
#line 2 "src/base/traits.hpp"

/**
 * @file traits.hpp
 * @brief 型特性
 */

#include <cstddef>
#line 11 "src/base/traits.hpp"
#include <type_traits>
#include <utility>

namespace detail {
using std::begin, std::end;

template <class T, class = void>
struct is_range_impl : std::false_type {};
template <class T>
struct is_range_impl<T, std::void_t<decltype(begin(std::declval<T&>()), end(std::declval<T&>()))>> : std::true_type {};
}  // namespace detail

template <class T>
struct is_range : detail::is_range_impl<T>::type {};
template <class T>
inline constexpr bool is_range_v = is_range<T>::value;

#define HAS_METHOD(func_name)                                                              \
    namespace detail {                                                                     \
    template <class T, class = void>                                                       \
    struct has_##func_name##_impl : std::false_type {};                                    \
    template <class T>                                                                     \
    struct has_##func_name##_impl<T, std::void_t<decltype(std::declval<T>().func_name())>> \
        : std::true_type {};                                                               \
    }                                                                                      \
    template <class T>                                                                     \
    struct has_##func_name : detail::has_##func_name##_impl<T>::type {};                   \
    template <class T>                                                                     \
    inline constexpr bool has_##func_name##_v = has_##func_name<T>::value;

#define HAS_METHOD_ARG(func_name)                                                                              \
    namespace detail {                                                                                         \
    template <class T, typename U, class = void>                                                               \
    struct has_##func_name##_impl : std::false_type {};                                                        \
    template <class T, typename U>                                                                             \
    struct has_##func_name##_impl<T, U, std::void_t<decltype(std::declval<T>().func_name(std::declval<U>()))>> \
        : std::true_type {};                                                                                   \
    }                                                                                                          \
    template <class T, typename U>                                                                             \
    struct has_##func_name : detail::has_##func_name##_impl<T, U>::type {};                                    \
    template <class T, typename U>                                                                             \
    inline constexpr bool has_##func_name##_v = has_##func_name<T, U>::value;

HAS_METHOD(repr)
HAS_METHOD(type_str)
HAS_METHOD(initializer_str)
HAS_METHOD(max)
HAS_METHOD(min)
HAS_METHOD(reversed)
HAS_METHOD(sorted)
HAS_METHOD(sum)
HAS_METHOD(product)
HAS_METHOD(product_xor)
HAS_METHOD_ARG(count)
HAS_METHOD_ARG(find)
HAS_METHOD_ARG(lower_bound)
HAS_METHOD_ARG(upper_bound)

#define ENABLE_IF_T_IMPL(expr) std::enable_if_t<expr, std::nullptr_t> = nullptr
#define ENABLE_IF_T(...) ENABLE_IF_T_IMPL((__VA_ARGS__))

template <class C>
using mem_value_type = typename C::value_type;
template <class C>
using mem_difference_type = typename C::difference_type;

namespace detail {
template <class T, class = void>
struct is_sorted_container_impl : std::false_type {};
template <class T>
struct is_sorted_container_impl<std::set<T>> : std::true_type {};
template <class T>
struct is_sorted_container_impl<std::multiset<T>> : std::true_type {};
}  // namespace detail
template <class T>
struct is_sorted_container : detail::is_sorted_container_impl<T>::type {};
template <class T>
inline constexpr bool is_sorted_container_v = is_sorted_container<T>::value;
#line 16 "src/base/container_func.hpp"

#define METHOD_EXPAND(func)                                        \
    template <typename T, ENABLE_IF_T(has_##func##_v<T>)>          \
    inline constexpr auto func(const T &t) -> decltype(t.func()) { \
        return t.func();                                           \
    }

#define METHOD_AND_FUNC_ARG_EXPAND(func)                                     \
    template <typename T, typename U, ENABLE_IF_T(has_##func##_v<T, U>)>     \
    inline constexpr auto func(const T &t, const U &u)                       \
        -> decltype(t.func(u)) {                                             \
        return t.func(u);                                                    \
    }                                                                        \
    template <typename T, typename U, ENABLE_IF_T(not has_##func##_v<T, U>)> \
    inline constexpr auto func(const T &t, const U &u)                       \
        -> decltype(std::func(t.begin(), t.end(), u)) {                      \
        return std::func(t.begin(), t.end(), u);                             \
    }

METHOD_EXPAND(reversed)
template <class C, ENABLE_IF_T(not has_reversed_v<C>)>
inline constexpr C reversed(C t) {
    std::reverse(t.begin(), t.end());
    return t;
}

METHOD_EXPAND(sorted)
template <class C, ENABLE_IF_T(not has_sorted_v<C>)>
inline constexpr C sorted(C t, bool reverse = false) {
    std::sort(t.begin(), t.end());
    if (reverse) std::reverse(t.begin(), t.end());
    return t;
}
template <class C, class F, ENABLE_IF_T(not has_sorted_v<C> and std::is_invocable_r_v<bool, F, mem_value_type<C>, mem_value_type<C>>)>
inline constexpr C sorted(C t, F f) {
    std::sort(t.begin(), t.end(), f);
    return t;
}

template <class C>
inline constexpr void sort(C &t, bool reverse = false) {
    std::sort(t.begin(), t.end());
    if (reverse) std::reverse(t.begin(), t.end());
}
template <class C, class F, ENABLE_IF_T(std::is_invocable_r_v<bool, F, mem_value_type<C>, mem_value_type<C>>)>
inline constexpr void sort(C &t, F f) {
    std::sort(t.begin(), t.end(), f);
}
template <class C, class F, ENABLE_IF_T(std::is_invocable_v<F, mem_value_type<C>>)>
inline constexpr void sort_by_key(C &t, F f) {
    std::sort(t.begin(), t.end(), [&](const mem_value_type<C> &left, const mem_value_type<C> &right) {
        return f(left) < f(right);
    });
}

template <class C>
inline constexpr void reverse(C &t) {
    std::reverse(t.begin(), t.end());
}

METHOD_EXPAND(max)
template <class C, ENABLE_IF_T(not has_max_v<C> and is_sorted_container_v<C>)>
inline constexpr mem_value_type<C> max(const C &v) {
    assert(v.begin() != v.end());
    return *v.rbegin();
}
template <class C, ENABLE_IF_T(not has_max_v<C> and not is_sorted_container_v<C>)>
inline constexpr mem_value_type<C> max(const C &v) {
    assert(v.begin() != v.end());
    return *std::max_element(v.begin(), v.end());
}
template <typename T>
inline constexpr T max(const std::initializer_list<T> &v) {
    return std::max(v);
}

METHOD_EXPAND(min)
template <class C, ENABLE_IF_T(not has_min_v<C> and is_sorted_container_v<C>)>
inline constexpr mem_value_type<C> min(const C &v) {
    assert(v.begin() != v.end());
    return *v.begin();
}
template <class C, ENABLE_IF_T(not has_min_v<C> and not is_sorted_container_v<C>)>
inline constexpr mem_value_type<C> min(const C &v) {
    assert(v.begin() != v.end());
    return *std::min_element(v.begin(), v.end());
}
template <typename T>
inline constexpr T min(const std::initializer_list<T> &v) {
    return std::min(v);
}

METHOD_EXPAND(sum)
template <class C, ENABLE_IF_T(not has_sum_v<C>)>
inline constexpr mem_value_type<C> sum(const C &v) {
    return std::accumulate(v.begin(), v.end(), mem_value_type<C>{});
}
template <typename T>
inline constexpr T sum(const std::initializer_list<T> &v) {
    return std::accumulate(v.begin(), v.end(), T{});
}

METHOD_EXPAND(product)
template <class C, ENABLE_IF_T(not has_product_v<C>)>
inline constexpr mem_value_type<C> product(const C &v) {
    return std::accumulate(v.begin(), v.end(), mem_value_type<C>{1}, std::multiplies<mem_value_type<C>>());
}
template <typename T>
inline constexpr T product(const std::initializer_list<T> &v) {
    return std::accumulate(v.begin(), v.end(), T{1}, std::multiplies<T>());
}

METHOD_EXPAND(product_xor)
template <class C, ENABLE_IF_T(not has_product_xor_v<C>)>
inline constexpr mem_value_type<C> product_xor(const C &v) {
    return std::accumulate(v.begin(), v.end(), mem_value_type<C>{0}, std::bit_xor<mem_value_type<C>>());
}
template <typename T>
inline constexpr T product_xor(const std::initializer_list<T> &v) {
    return std::accumulate(v.begin(), v.end(), T{0}, std::bit_xor<T>());
}

template <class C>
inline constexpr mem_value_type<C> maximum_subarray(const C &v) {
    assert(not v.empty());
    auto itr = v.begin();
    mem_value_type<C> tmp = *itr++;
    mem_value_type<C> res = tmp;
    while (itr != v.end()) {
        tmp += *itr;
        if (tmp < *itr) tmp = *itr;
        if (res < tmp) res = tmp;
        ++itr;
    }
    return res;
}
template <class C>
inline constexpr mem_value_type<C> maximum_subarray(const C &v, mem_value_type<C> init) {
    mem_value_type<C> res = init, tmp = init;
    for (const auto &a : v) {
        tmp += a;
        if (tmp < init) tmp = init;
        if (res < tmp) res = tmp;
    }
    return res;
}

METHOD_AND_FUNC_ARG_EXPAND(count)
METHOD_AND_FUNC_ARG_EXPAND(find)
METHOD_AND_FUNC_ARG_EXPAND(lower_bound)
METHOD_AND_FUNC_ARG_EXPAND(upper_bound)

template <class C, typename T>
inline constexpr bool contains(const C &c, const T &t) {
    return find(c, t) != c.end();
}

template <class C>
inline constexpr mem_value_type<C> gcd(const C &v) {
    mem_value_type<C> init(0);
    for (const auto &e : v) init = std::gcd(init, e);
    return init;
}

template <class C>
inline constexpr mem_value_type<C> average(const C &v) {
    assert(v.size());
    return sum(v) / v.size();
}

template <class C>
inline constexpr mem_value_type<C> median(const C &v) {
    assert(not v.empty());
    std::vector<size_t> u(v.size());
    std::iota(u.begin(), u.end(), 0);
    std::sort(u.begin(), u.end(), [&](size_t a, size_t b) {
        return v[a] < v[b];
    });
    if (v.size() & 1) {
        return v[u[v.size() / 2]];
    }
    // C++20
    // return std::midpoint(v[u[v.size() / 2]], v[u[v.size() / 2 - 1]]);
    return (v[u[v.size() / 2]] + v[u[v.size() / 2 - 1]]) / 2;
}

template <class C, typename U>
inline constexpr std::ptrdiff_t index(const C &v, const U &x) {
    return std::distance(v.begin(), find(v, x));
}

template <class C, ENABLE_IF_T(std::is_integral_v<mem_value_type<C>>)>
inline constexpr mem_value_type<C> mex(const C &v) {
    std::vector<bool> b(v.size() + 1);
    for (const auto &a : v) {
        if (0 <= a and static_cast<size_t>(a) < b.size()) {
            b[a] = true;
        }
    }
    mem_value_type<C> ret = 0;  // b の要素数は v より 1 多いので、下のループで必ず見つかる
    for (size_t i = 0; i < b.size(); i++) {
        if (not b[i]) {
            ret = i;
            break;
        }
    }
    return ret;
}

template <class C>
inline constexpr mem_difference_type<C> bisect_left(const C &v, const mem_value_type<C> &x) {
    return std::distance(v.begin(), lower_bound(v, x));
}
template <class C>
inline constexpr mem_difference_type<C> bisect_right(const C &v, const mem_value_type<C> &x) {
    return std::distance(v.begin(), upper_bound(v, x));
}
#line 16 "test/unittest/container-func.test.cpp"

bool ok = true;

void check(bool cond, const char* what) {
    if (!cond) {
        if (ok) std::cerr << "failed: " << what << std::endl;
        ok = false;
    }
}

int main() {
    std::mt19937_64 rng(314);
    auto rand_vec = [&](int n, long long lo, long long hi) {
        std::vector<long long> v(n);
        for (auto& x : v) x = lo + (long long)(rng() % (unsigned long long)(hi - lo + 1));
        return v;
    };

    for (int rep = 0; rep < 2000 && ok; rep++) {
        int n = rng() % 10 + 1;
        std::vector<long long> v = rand_vec(n, -5, 5);

        // sorted / sort (比較関数つき)
        {
            std::vector<long long> expect = v;
            std::sort(expect.begin(), expect.end(), std::greater<long long>());
            check(sorted(v, std::greater<long long>()) == expect, "sorted(c, f)");
            std::vector<long long> w = v;
            sort(w, std::greater<long long>());
            check(w == expect, "sort(c, f)");
        }

        // set / multiset に対する max / min (ソート済みのコンテナは先頭と末尾)
        {
            std::set<long long> s(v.begin(), v.end());
            std::multiset<long long> ms(v.begin(), v.end());
            long long mx = *std::max_element(v.begin(), v.end());
            long long mn = *std::min_element(v.begin(), v.end());
            check(max(s) == mx && min(s) == mn, "max/min(set)");
            check(max(ms) == mx && min(ms) == mn, "max/min(multiset)");
            check(max(v) == mx && min(v) == mn, "max/min(vector)");
        }

        // product / product_xor
        {
            std::vector<long long> small = rand_vec(n, -3, 3);
            long long p = 1, x = 0;
            for (long long a : small) p *= a, x ^= a;
            check(product(small) == p, "product(c)");
            check(product_xor(small) == x, "product_xor(c)");
            std::vector<long long> nonneg = rand_vec(n, 0, 1000000);
            long long y = 0;
            for (long long a : nonneg) y ^= a;
            check(product_xor(nonneg) == y, "product_xor(c) large");
        }

        // maximum_subarray (空の部分列を許す版): 全区間の和の最大値と init の大きい方
        {
            long long init = (long long)(rng() % 7) - 3;
            long long best = init;
            for (int l = 0; l < n; l++) {
                long long s = init;
                for (int r = l; r < n; r++) {
                    s += v[r];
                    best = std::max(best, s);
                }
            }
            check(maximum_subarray(v, init) == best, "maximum_subarray(c, init)");
            // 空でない版も合わせて確かめる
            long long best_nonempty = v[0];
            for (int l = 0; l < n; l++) {
                long long s = 0;
                for (int r = l; r < n; r++) {
                    s += v[r];
                    best_nonempty = std::max(best_nonempty, s);
                }
            }
            check(maximum_subarray(v) == best_nonempty, "maximum_subarray(c)");
        }

        // median: 偶数個なら中央 2 つの平均 (整数型は 0 方向に切り捨て)
        {
            std::vector<long long> w = v;
            std::sort(w.begin(), w.end());
            long long expect = n % 2 ? w[n / 2] : (w[n / 2 - 1] + w[n / 2]) / 2;
            check(median(v) == expect, "median(vector<long long>)");
            std::vector<double> d(v.begin(), v.end());
            std::vector<double> dw = d;
            std::sort(dw.begin(), dw.end());
            double dexp = n % 2 ? dw[n / 2] : (dw[n / 2 - 1] + dw[n / 2]) / 2;
            check(median(d) == dexp, "median(vector<double>)");
        }

        // index: 最初に現れる位置、なければ size
        {
            long long x = (long long)(rng() % 13) - 6;
            long long expect = std::find(v.begin(), v.end(), x) - v.begin();
            check(index(v, x) == expect, "index(c, x)");
        }

        // mex: 含まれない最小の非負整数
        {
            std::vector<int> w(n);
            for (auto& a : w) a = (int)(rng() % 8) - 2;
            int expect = 0;
            while (std::find(w.begin(), w.end(), expect) != w.end()) expect++;
            check(mex(w) == expect, "mex(c)");
        }

        // count / find / lower_bound / upper_bound (set はメンバ関数、vector は std:: のアルゴリズム)
        {
            long long x = (long long)(rng() % 13) - 6;
            std::multiset<long long> ms(v.begin(), v.end());
            std::vector<long long> w = v;
            std::sort(w.begin(), w.end());
            check(count(ms, x) == (std::size_t)std::count(v.begin(), v.end(), x), "count(multiset, x)");
            check(count(v, x) == std::count(v.begin(), v.end(), x), "count(vector, x)");
            check((find(ms, x) != ms.end()) == (std::find(v.begin(), v.end(), x) != v.end()), "find(multiset, x)");
            check(find(v, x) == std::find(v.begin(), v.end(), x), "find(vector, x)");
            check(lower_bound(ms, x) == ms.lower_bound(x) && upper_bound(ms, x) == ms.upper_bound(x), "lower/upper_bound(multiset, x)");
            check(lower_bound(w, x) == std::lower_bound(w.begin(), w.end(), x), "lower_bound(vector, x)");
            check(upper_bound(w, x) == std::upper_bound(w.begin(), w.end(), x), "upper_bound(vector, x)");
            check(contains(v, x) == (std::find(v.begin(), v.end(), x) != v.end()), "contains(vector, x)");
        }
    }

    // 初期化子リスト版
    check(max({3, -1, 7, 2}) == 7, "max(initializer_list)");
    check(min({3, -1, 7, 2}) == -1, "min(initializer_list)");
    check(sum({3, -1, 7, 2}) == 11, "sum(initializer_list)");
    check(product({3, -1, 7, 2}) == -42, "product(initializer_list)");
    check(product_xor({3, 5, 6}) == 0, "product_xor(initializer_list)");
    check(max({5}) == 5 && min({5}) == 5, "max/min(initializer_list) 1 要素");

    // 境界: 1 要素、空
    check(median(std::vector<int>{4}) == 4, "median 1 要素");
    check(median(std::vector<int>{1, 4}) == 2, "median 2 要素");
    check(mex(std::vector<int>{}) == 0, "mex 空");
    check(mex(std::vector<int>{0, 1, 2}) == 3, "mex 0..n-1 をすべて含む");
    check(maximum_subarray(std::vector<int>{}, 0) == 0, "maximum_subarray 空");
    check(maximum_subarray(std::vector<int>{-5, -2, -9}) == -2, "maximum_subarray すべて負");
    check(maximum_subarray(std::vector<int>{-5, -2, -9}, 0) == 0, "maximum_subarray すべて負、空を許す");
    check(product(std::vector<int>{}) == 1 && product_xor(std::vector<int>{}) == 0, "product 空");
    check(index(std::vector<int>{}, 3) == 0, "index 空");
    check(sorted(std::string("bca"), std::greater<char>()) == "cba", "sorted(string, f)");

    if (ok) std::cout << "Hello World" << std::endl;
}
Back to top page