This documentation is automatically generated by online-judge-tools/verification-helper
#include "Src/Utility/BinarySearch.hpp"
整数や実数を一つ引数にとり、真理値を返り値とする関数 $f$ を考えます。 $f$ に以下の性質の一方を満たすと仮定します。
このような場合で、 $m$ を発見して返します。
(1)
template<class T, class Function>
T BinarySearch(T ok, T ng, const Function& f)
(2)
template<class T, class Function>
T BinarySearch(T ok, T ng, const Functioni& f, u32 upperLimit)
T
f
の引数の型です。制約:
(1) 整数型であること
(2) 算術型であること
Function
f
の型です。制約:
T
型の値を一つ引数にとり、bool
値を返り値とする関数オブジェクトであることok
制約: f(ok) = true
を満たすこと
ng
制約: f(ng) = false
を満たすこと
f
制約: 概要の条件を満たすこと
upperLimit
探索回数の上限を設定します。
$m$ を返します。
(1) f
を $\mid \text{ok} - \text{ng}\mid$ 回呼び出します。
(2) f
をupperLimit
回呼び出します。
名前の通り、二分探索しています。
所謂、めぐる式二分探索を採用しています。
2023/9/24: (1)においてunsignedな整数型も利用できるように修正しました。オーバーフローする問題を解消しました。
#pragma once
#include "../Template/TypeAlias.hpp"
#include <cmath>
#include <functional>
#include <type_traits>
#include <utility>
namespace zawa {
namespace internal {
template <class T>
T MidPoint(T a, T b) {
if (a > b) std::swap(a, b);
return a + ((b - a) >> 1);
}
template <class T>
T Abs(T a, T b) {
return (a >= b ? a - b : b - a);
}
} // namespace zawa::internal
template <class T, class Function>
T BinarySearch(T ok, T ng, const Function& f) {
static_assert(std::is_integral_v<T>, "T must be integral type");
static_assert(std::is_convertible_v<Function, std::function<bool(T)>>, "f must be function bool(T)");
while (internal::Abs(ok, ng) > 1) {
T mid{ internal::MidPoint(ok, ng) };
(f(mid) ? ok : ng) = mid;
}
return ok;
}
template <class T, class Function>
T BinarySearch(T ok, T ng, const Function& f, u32 upperLimit) {
static_assert(std::is_signed_v<T>, "T must be signed arithmetic type");
static_assert(std::is_convertible_v<Function, std::function<bool(T)>>, "f must be function bool(T)");
for (u32 _{} ; _ < upperLimit ; _++) {
T mid{ (ok + ng) / (T)2 };
(f(mid) ? ok : ng) = mid;
}
return ok;
}
} // namespace zawa
#line 2 "Src/Utility/BinarySearch.hpp"
#line 2 "Src/Template/TypeAlias.hpp"
#include <cstdint>
#include <cstddef>
namespace zawa {
using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using i128 = __int128_t;
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using usize = std::size_t;
} // namespace zawa
#line 4 "Src/Utility/BinarySearch.hpp"
#include <cmath>
#include <functional>
#include <type_traits>
#include <utility>
namespace zawa {
namespace internal {
template <class T>
T MidPoint(T a, T b) {
if (a > b) std::swap(a, b);
return a + ((b - a) >> 1);
}
template <class T>
T Abs(T a, T b) {
return (a >= b ? a - b : b - a);
}
} // namespace zawa::internal
template <class T, class Function>
T BinarySearch(T ok, T ng, const Function& f) {
static_assert(std::is_integral_v<T>, "T must be integral type");
static_assert(std::is_convertible_v<Function, std::function<bool(T)>>, "f must be function bool(T)");
while (internal::Abs(ok, ng) > 1) {
T mid{ internal::MidPoint(ok, ng) };
(f(mid) ? ok : ng) = mid;
}
return ok;
}
template <class T, class Function>
T BinarySearch(T ok, T ng, const Function& f, u32 upperLimit) {
static_assert(std::is_signed_v<T>, "T must be signed arithmetic type");
static_assert(std::is_convertible_v<Function, std::function<bool(T)>>, "f must be function bool(T)");
for (u32 _{} ; _ < upperLimit ; _++) {
T mid{ (ok + ng) / (T)2 };
(f(mid) ? ok : ng) = mid;
}
return ok;
}
} // namespace zawa