1
1
#include < cmath>
2
2
#include < cstdio>
3
- #include < vector>
4
- #include < iostream>
3
+ #include < ctime>
5
4
#include < algorithm>
5
+ #include < iostream>
6
+ #include < vector>
6
7
using namespace std ;
7
8
8
9
struct element {
@@ -14,29 +15,112 @@ struct element {
14
15
}
15
16
};
16
17
17
- size_t lower_bound (const vector<element>& flavors, const int search) {
18
- if (flavors.empty ()) {
19
- return -1 ;
18
+ template <typename T>
19
+ size_t lower_bound (const vector<T>& arr, const T& search) {
20
+ if (arr.empty ()) {
21
+ return arr.size ();
20
22
}
21
23
24
+ // binary search
22
25
size_t begin = 0 ;
23
- size_t end = flavors .size ();
24
- while (begin + 1 != end) {
26
+ size_t end = arr .size () - 1 ;
27
+ while (begin < end) {
25
28
// (begin + end) / 2 can cause overflow
26
29
size_t middle = begin + (end - begin) / 2 ;
27
- if (search < flavors[middle].value ) {
30
+ if (arr[middle] < search) {
31
+ // search right half
32
+ begin = middle + 1 ;
33
+ } else {
28
34
// search left half
29
35
end = middle;
30
- } else {
31
- // search right half
32
- begin = middle;
33
36
}
34
37
}
35
38
39
+ // all values are less than search
40
+ if (arr[begin] < search) {
41
+ return arr.size ();
42
+ }
36
43
return begin;
37
44
}
38
45
46
+ template <typename T>
47
+ size_t linear_scan_lower_bound (const vector<T>& arr, const T& search) {
48
+ size_t i = 0 ;
49
+ for ( ; i < arr.size (); i++) {
50
+ if (!(arr[i] < search)) {
51
+ return i;
52
+ }
53
+ }
54
+ return arr.size ();
55
+ }
56
+
57
+ void test (vector<int >& arr, int search) {
58
+ size_t linear = linear_scan_lower_bound (arr, search);
59
+ size_t bsearch = lower_bound (arr, search);
60
+ auto it = std::lower_bound (arr.begin (), arr.end (), search);
61
+ size_t std = it - arr.begin ();
62
+ if (linear != bsearch || std != bsearch ) {
63
+ cout << " key = " << search << endl
64
+ << " linear = " << linear << endl
65
+ << " binary = " << bsearch << endl
66
+ << " lower_bound = " << std << endl;
67
+ if (arr.size () <= 100 ) {
68
+ for (auto a : arr) {
69
+ cout << a << ' ' ;
70
+ }
71
+ }
72
+ cout << endl << endl;
73
+ }
74
+ }
75
+
76
+ void test_lower_bound () {
77
+ // fixed test cases
78
+ {
79
+ vector<int > arr = {};
80
+ for (int i = 0 ; i <= 7 ; i++) {
81
+ test (arr, i);
82
+ }
83
+ }
84
+ {
85
+ vector<int > arr = {2 };
86
+ for (int i = 0 ; i <= 7 ; i++) {
87
+ test (arr, i);
88
+ }
89
+ }
90
+ {
91
+ vector<int > arr = {2 , 5 };
92
+ for (int i = 0 ; i <= 7 ; i++) {
93
+ test (arr, i);
94
+ }
95
+ }
96
+ {
97
+ vector<int > arr = {5 , 10 , 15 , 20 , 25 , 30 };
98
+ for (int i = 0 ; i <= 35 ; i++) {
99
+ test (arr, i);
100
+ }
101
+ }
102
+
103
+ // randomized test cases
104
+ srand (time (NULL ));
105
+ {
106
+ const auto max = 10000 ;
107
+ vector<int > arr;
108
+ arr.reserve (max);
109
+ const auto tries = 1000 * 1000 ;
110
+ for (int t = 0 ; t < tries; t++) {
111
+ arr.clear ();
112
+ auto currmax = rand () % max;
113
+ for (int i = 0 ; i < max; i++) {
114
+ arr.push_back (rand () % max);
115
+ }
116
+ sort (arr.begin (), arr.end ());
117
+ test (arr, rand () % max);
118
+ }
119
+ }
120
+ }
121
+
39
122
int main () {
123
+ if (false ) { test_lower_bound (); return 0 ; }
40
124
int T = 0 ;
41
125
cin >> T;
42
126
for (int t = 0 ; t < T; t++) {
@@ -56,7 +140,7 @@ int main() {
56
140
sort (flavors.begin (), flavors.end ());
57
141
for (auto flavor : flavors) {
58
142
int need = M - flavor.value ;
59
- size_t lbound = lower_bound (flavors, need);
143
+ size_t lbound = lower_bound (flavors, { need, 0 } );
60
144
if (lbound != -1 ) {
61
145
auto & other_flavor = flavors[lbound];
62
146
if (other_flavor.value == need && flavor.index != other_flavor.index ) {
0 commit comments