二分的本质并不是单调性。
有单调性一定可以二分,但是可以二分的题目不一定有单调性。
我们找一个性质:使得整个区间可以被划分为两个左右区间,一边满足这个性质,一边不满足这个性质,中间没有交点。二分就可以寻找这个性质的边界。
上红下绿。
每次二分时都选择答案所在的区间进行操作,每一次都保证区间里一定有答案,当区间长度是1的时候,答案一定就是它。
注意:二分的时候一定是有解的,可能题目无解,不过二分一定有解。
我们定义的这个性质一定有边界,二分一定可以把边界二分出来。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 100010; 4 int a[N]; 5 int main () { 6 int n, q; 7 cin >> n >> q; 8 for (int i = 0; i < n; i++) { 9 cin >> a[i]; 10 } 11 while (q--) { 12 int x; 13 cin >> x; 14 int l = 0, r = n - 1; 15 while (l < r) { 16 int mid = l + r >> 1; 17 if (a[mid] >= x) { 18 r = mid; 19 } else { 20 l = mid + 1; 21 } 22 } 23 //如果我们这个序列中不存在x的话,那么我们二分出来的是个啥东西呢 24 //二分出来的是从左往右最前面的那个满足>=x的那个数 25 if (a[l] != x) { 26 cout << "-1 -1" << endl; 27 } else { 28 cout << l << " "; //此处输出l或r都是一样的,因为当这个while循环结束的时候,l=r 29 int l = 0, r = n - 1; 30 while (l < r) { 31 int mid = l + r + 1 >> 1; 32 if (a[mid] <= x) { 33 l = mid; 34 } else { 35 r = mid - 1; 36 } 37 } 38 cout << l << endl; 39 } 40 } 41 return 0; 42 }