数的范围

    技术2022-07-11  79

    给定一个按照升序排列的长度为n的整数数组,以及 q 个查询。

    对于每个查询,返回一个元素k的起始位置和终止位置(位置从0开始计数)。

    如果数组中不存在该元素,则返回“-1 -1”。

    输入格式 第一行包含整数n和q,表示数组长度和询问个数。

    第二行包含n个整数(均在1~10000范围内),表示完整数组。

    接下来q行,每行包含一个整数k,表示一个询问元素。

    输出格式 共q行,每行包含两个整数,表示所求元素的起始位置和终止位置。

    如果数组中不存在该元素,则返回“-1 -1”。

    数据范围 1≤n≤100000 1≤q≤10000 1≤k≤10000 输入样例: 6 3 1 2 2 3 3 4 3 4 5 输出样例: 3 4 5 5 -1 -1

    在单调序列中查>=x的数中最小的一个数

    while(l<r){ int mid=(r+l)>>1; if(a[mid]>=x) r=mid; else l=mid+1; }

    在代码中,如果a[mid]>=x,根据数列的单调性,mid之后的数会更大,所以大于等于x的最小的数不可能在mid的后面;将区间减小为左半段因为mid也可能是答案,所以r=mid,如果a[mid]<x,则l=mid+1

    在单调序列中查找<=x的最大的一个数

    while(l<r) { int mid=(l+r+1)>>1; if(a[mid]<=m) l=mid; else r=mid-1; }

    *在代码中,如果a[mid]<=x,根据数列的单调性,mid之后的数会更小,所以小于等于x的最大的数不可能在mid的前面;将区间减小为右半段因为mid也可能是答案,所以l=mid,如果a[mid]>x,则l=mid-1 如果不对mid加以区分,第二段也用mid=(l+r)>>1;则当r-l=1时,mid=([pl+r)/2]=l; 然后进入l=mid的分支,然后会死循环。要是进入r=mid-1分支,循环不能以l=r结束。

    #include<iostream> using namespace std; const int N=100010; int a[N],n,q; int main(){ cin>>n>>q; for(int i=0;i<n;i++) cin>>a[i]; while(q--){ int m; int l=0,r=n-1; cin>>m; while(l<r){ int mid=(r+l)>>1; if(a[mid]>=m) r=mid; else l=mid+1; } if(a[l]!=m) printf("-1 -1\n"); else{ cout<<l<<" "; int l=0,r=n-1; while(l<r) { int mid=(l+r+1)>>1; if(a[mid]<=m) l=mid; else r=mid-1; } cout<<l<<endl; }} return 0; }
    Processed: 0.012, SQL: 9