一. AcWing789_数的范围
二. 理论
对于本题给定一个升序序列,查找元素k的起始位置和终止位置,只需分别使用二分查找起始位置和终止位置即可。
对于起始位置,即查找最左边的元素k的位置,二分的更新则使用mid=r,不断靠近左边
三. 代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int n, m, k;
int q[N];
//朴素二分类
class Dichotomy
{
public:
static void initIO()
{
// 关闭输入输出缓存,使效率提升
ios::sync_with_stdio(false);
// 解除cin和cout的默认绑定,来降低IO的负担使效率提升
cin.tie(nullptr);
cout.tie(nullptr);
}
/**
* 查找左边界
* @param l 区间左值
* @param r 区间右值
* @param x 要查找的值
* @return 返回左边界下标,没有则返回-1。
*/
int findl(int l, int r, int x)
{
while(l<r)
{
int mid=(l+r)/2;
if(q[mid]>=x) r=mid;
else l=mid+1;
}
return l;
}
/**
* 查找右边界
* @param l 区间左值
* @param r 区间右值
* @param x 要查找的值
* @return 返回右边界下标,没有则返回-1。
*/
int findr(int l, int r, int x)
{
while(l<r)
{
int mid=(l+r+1)/2;
if(q[mid]<=x) l=mid;
else r=mid-1;//出现mid-1,则上面(l+r+1)而不是(l+r)防止死循环
}
return l;
}
};
int main()
{
Dichotomy::initIO();
cin>>n>>m;
for(int i=0;i<n;++i)
cin>>q[i];
Dichotomy dichotomy;
while(m--)
{
cin>>k;
int idx=dichotomy.findl(0, n-1, k);
if(q[idx]!=k) cout<<"-1 -1"<<endl;
else cout<<idx<<" "<<dichotomy.findr(0, n-1, k)<<endl;
}
}