Skip to main content

nekolib/traits/
bisect.rs

1//! 二分探索。
2
3use std::ops::{Range, RangeFrom, RangeTo};
4
5/// 二分探索。
6///
7/// $\\gdef\\halfopen#1#2{[#1, #2)}$
8/// 述語 $f$ は、ある $x$ に対して次が成り立つとする。
9/// - $y\\in\\halfopen{L}{x} \\implies f(y)$
10/// - $y\\in\\halfopen{x}{R} \\implies \\lnot f(y)$
11///
12/// この $x$ を返す。
13///
14/// # Idea
15/// - `RangeFrom<u32>` などに関しては [指数探索](https://rsk0315.hatenablog.com/entry/2021/12/19/124017)。
16/// - `Range<f64>` などに関しては [ビット表現を整数と見て二分探索](https://rsk0315.hatenablog.com/entry/2022/04/07/004618)。
17///
18/// # Notes
19/// 下端が条件を満たすかを判定するのが不都合なときは、下端を一つ大きく取って別で処理するとよいかも。
20/// cf. [提出 #34955711](https://atcoder.jp/contests/abc269/submissions/34955711)
21///
22/// # Examples
23/// ```
24/// use nekolib::traits::Bisect;
25///
26/// let pred = |&x: &i32| x * x < 200;
27/// assert_eq!((0..100).bisect(pred), 15);
28/// assert_eq!((0..).bisect(pred), 15);
29///
30/// let a = [0, 1, 4, 5, 5, 5, 9];
31/// let pred = |&x: &i32| x < 5;
32/// assert_eq!(a.bisect(pred), 3);
33/// assert_eq!(a[5..].bisect(pred), 0); // [5, 9]
34/// assert_eq!(a[..0].bisect(pred), 0); // []
35///
36/// let pred = |&x: &f64| 2.0_f64.powf(x) < 3.0;
37/// let lg3 = 3.0_f64.log2();
38/// // 1.584962500721156
39/// assert!(((1.0_f64..2.0).bisect(pred) - lg3).abs() <= 1e-16);
40/// assert_eq!((1.0_f64..2.0).bisect(pred), lg3); // !
41/// ```
42pub trait Bisect {
43    type Input;
44    type Output;
45    fn bisect(&self, pred: impl FnMut(&Self::Input) -> bool) -> Self::Output;
46}
47
48macro_rules! impl_bisect_int {
49    ($t:ty) => {
50        impl Bisect for Range<$t> {
51            type Input = $t;
52            type Output = $t;
53            fn bisect(&self, mut pred: impl FnMut(&$t) -> bool) -> $t {
54                let Range { start: mut ok, end: mut bad } = *self;
55                if !pred(&ok) {
56                    return ok;
57                }
58                while bad - ok > 1 {
59                    let mid = ok + (bad - ok) / 2;
60                    *(if pred(&mid) { &mut ok } else { &mut bad }) = mid;
61                }
62                bad
63            }
64        }
65
66        impl Bisect for RangeFrom<$t> {
67            type Input = $t;
68            type Output = $t;
69            fn bisect(&self, mut pred: impl FnMut(&$t) -> bool) -> $t {
70                let RangeFrom { start: ok } = *self;
71                if !pred(&ok) {
72                    return ok;
73                }
74                let mut w = 1;
75                while pred(&(ok + w)) {
76                    w *= 2;
77                }
78                (ok..ok + w).bisect(pred)
79            }
80        }
81
82        impl Bisect for RangeTo<$t> {
83            type Input = $t;
84            type Output = $t;
85            fn bisect(&self, mut pred: impl FnMut(&$t) -> bool) -> $t {
86                let RangeTo { end: bad } = *self;
87                if pred(&bad) {
88                    return bad;
89                }
90                let mut w = 1;
91                while !pred(&(bad - w)) {
92                    w *= 2;
93                }
94                (bad - w..bad).bisect(pred)
95            }
96        }
97
98    };
99    ( $( $t:ty )* ) => { $( impl_bisect_int! { $t } )* };
100}
101
102impl_bisect_int! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
103
104macro_rules! impl_bisect_float {
105    (
106        $(
107            (
108                $fty:ty, $ity:ty, $uty:ty, $w:literal,
109                $f2u:ident, $u2f:ident, $mask:ident
110            ),
111        )*
112    ) => { $(
113        impl Bisect for Range<$fty> {
114            type Input = $fty;
115            type Output = $fty;
116            fn bisect(&self, mut pred: impl FnMut(&$fty) -> bool) -> $fty {
117                let Range { start, end } = *self;
118                let start = $f2u(start);
119                let end = $f2u(end);
120                $u2f((start..end).bisect(|&u| pred(&$u2f(u))))
121            }
122        }
123        fn $mask(u: $uty) -> $uty {
124            ((u as $ity >> ($w - 1)) as $uty >> 1) | 1 << ($w - 1)
125        }
126        fn $f2u(f: $fty) -> $uty {
127            let u = f.to_bits();
128            u ^ $mask(u)
129        }
130        fn $u2f(u: $uty) -> $fty { <$fty>::from_bits(u ^ $mask(!u)) }
131    )* };
132}
133
134impl_bisect_float! {
135    (f32, i32, u32, 32, f2u32, u2f32, mask32),
136    (f64, i64, u64, 64, f2u64, u2f64, mask64),
137}
138
139impl<T> Bisect for [T] {
140    type Input = T;
141    type Output = usize;
142    fn bisect(&self, mut pred: impl FnMut(&T) -> bool) -> usize {
143        if self.is_empty() || !pred(&self[0]) {
144            return 0;
145        }
146        let mut ok = 0;
147        let mut bad = self.len();
148        while bad - ok > 1 {
149            let mid = ok + (bad - ok) / 2;
150            *(if pred(&self[mid]) { &mut ok } else { &mut bad }) = mid;
151        }
152        bad
153    }
154}
155
156#[test]
157fn test() {
158    {
159        let pred = |&x: &i64| x < 100;
160        assert_eq!((0_i64..200).bisect(pred), 100);
161        assert_eq!((0_i64..).bisect(pred), 100);
162        assert_eq!((..200_i64).bisect(pred), 100);
163    }
164
165    {
166        let pred = |&x: &i64| x.abs() < 100;
167        assert_eq!((0_i64..200).bisect(pred), 100);
168        assert_eq!((0_i64..).bisect(pred), 100);
169        assert_eq!((..0_i64).bisect(|x| !pred(x)), -99);
170    }
171
172    {
173        let pred = |&x: &i64| x < 5;
174        let a = vec![0, 1, 4, 5, 5, 9];
175        assert_eq!(a.bisect(pred), 3);
176        assert_eq!(a[4..].bisect(pred), 0);
177    }
178
179    {
180        let pred = |&x: &f64| 2.0_f64.powf(x) < 3.0;
181        assert!(((1.0_f64..2.0).bisect(pred) - 3.0_f64.log2()) <= 5.0e-324);
182        // println!("{:.40}", 3.0_f64.log2());
183        // println!("{:.40}", (1.0_f64..2.0).bisect(pred));
184    }
185    {
186        assert_eq!([0, 1, 4, 5, 9].bisect(|&x: &i32| x < 5), 3);
187        assert_eq!((0..100).bisect(|&x: &i32| x * x < 200), 15);
188        assert_eq!((0..).bisect(|&x: &i32| x * x < 200), 15);
189    }
190    {
191        let pred = |&x: &i32| x * x < 200;
192        assert_eq!((0..100).bisect(pred), 15);
193        assert_eq!((0..).bisect(pred), 15);
194    }
195}