整数二分
本质:可以使区间被分为两部分,其中一部分满足性质A,另一部分不满足性质A,即可使用二分
模板一:取左部分的右端点
1 2 3 4 5 6 7
| mid=(l+r+1)>>1; if(check(mid)){ l=mid; } else{ r=mid-1; }
|
模板二:取右部分的左端点
1 2 3 4 5 6 7
| mid=l+r>>1; if(check(mid)){ r=mid; } else{ l=mid+1; }
|
例题:输入一个排好序的数组,求给定数的起始位置和终止位置
分析:求起始位置可以把区间分为$<x,\ge x$两部分,取右部分的左端点;
求终止位置可以把区间分为$\le x,>x$两部分,取左部分的右端点。
代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #include<bits/stdc++.h> using namespace std;
const int N=1e6; int n,Q; int q[N];
int find_l(int k){ int l=1,r=n; while(l<r){ int mid=l+r>>1; if(q[mid]>=k){ r=mid; } else{ l=mid+1; } } if(q[l]!=k)return 0; return l; }
int find_r(int k){ int l=1,r=n; while(l<r){ int mid=l+r+1>>1; if(q[mid]<=k){ l=mid; } else{ r=mid-1; } } if(q[r]!=k)return 0; return r; }
int main(){ cin >> n >> Q; for(int i=1;i<=n;i++){ cin >> q[i]; } for(int i=1;i<=Q;i++){ int x; cin >> x; cout << find_l(x)-1 << ' ' << find_r(x)-1 << endl; } return 0; }
|