解题思路
本题针对整数二分。首先根据题意将整个区间划分为左右两个部分,此时的左右两个部分不一定是平分开的,而是根据题意中的某种性质划分开的,比如本道题中,选择x的起始位置时可以将性质定义为:x右边的数都≥x,选择x的结束位置时可以将性质定义为:x左边的数都≤x。然后判断mid值在左右哪个区间,进而缩短判定区间的范围,更新区间的端点值。
整数二分算法模板
bool check(int x) {/* ... */} // 检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1;
}
return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
C++ 代码
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int q[N];
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]);
while (m -- )
{
int x;
scanf("%d", &x);
int l = 0, r = n - 1;
while(l < r)
{
// 寻找x的起始位置,定义性质:x后面的数都≥x
int mid = l + r >> 1;
// mid在右半边,答案在左半边,并且mid是有可能取到答案的
if(q[mid] >= x) r = mid;
else l = mid + 1;
}
// 序列中不存在x值
if(q[l] != x) cout << "-1 -1" << endl;
else
{
cout << l <<' '; //此时输出l和输出r是一样的,因为while循环结束后l=r
// 寻找最后一个x的位置,定义性质:x前面的数据都≤x
int l = 0, r = n - 1;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (q[mid] <= x) l = mid;
else r = mid - 1;
}
cout << l << endl;
}
}
return 0;
}