二分笔记
2026-07-14 20:35:49
发布于:广东
1. 查找 x 是否存在
思路简介
数组有序时,可以用二分查找。
#include<bits/stdc++.h>
using namespace std;
int a[100010];
int n,x;
int main(){
cin >> n;
// 输入有序数组
for(int i = 1; i <= n; i++) cin >> a[i];
cin >> x;
// 二分查找的左右边界
int l = 1, r = n;
while(l <= r){
int mid = (l + r) / 2;
if(a[mid] < x){
// 中间值比 x 小,说明 x 只可能在右边
l = mid + 1;
}else if(a[mid] > x){
// 中间值比 x 大,说明 x 只可能在左边
r = mid - 1;
}else{
// 找到 x,输出下标
cout << mid;
return 0;
}
}
// 循环结束还没找到,说明不存在
cout << -1;
return 0;
}
2. 手写 lower_bound:查找第一个 >= x 的位置
思路简介
要找的是第一个满足:
a[i] >= x
的位置。
二分时,如果:
a[mid] >= x
说明 mid 可能是答案,但是前面可能还有更靠左的答案,所以:
ans = mid;
r = mid - 1;
如果:
a[mid] < x
说明 mid 和左边都太小了,所以往右找:
l = mid + 1;
如果不存在,输出 n + 1。
带注释代码
#include<bits/stdc++.h>
using namespace std;
int a[200010];
int n,x,q;
int main(){
cin >> n >> q;
// 输入有序数组
for(int i = 1; i <= n; i++) cin >> a[i];
while(q--){
cin >> x;
int l = 1, r = n;
// ans 表示第一个 >= x 的位置
// 如果找不到,默认是 n + 1
int ans = n + 1;
while(l <= r){
int mid = (l + r) / 2;
if(a[mid] >= x){
// a[mid] 已经满足 >= x
// 先记录答案
ans = mid;
// 但题目要第一个位置,所以继续往左找
r = mid - 1;
}else{
// a[mid] < x,说明 mid 和左边都不满足
// 只能往右找
l = mid + 1;
}
}
cout << ans << endl;
}
return 0;
}
3. STL lower_bound:第一个 >= x
思路简介
lower_bound 的含义是:
找第一个大于等于 x 的位置
写法:
lower_bound(a + 1, a + n + 1, x)
返回的是地址。
要转成下标,需要减去数组首地址:
lower_bound(a + 1, a + n + 1, x) - a
带注释代码
#include<bits/stdc++.h>
using namespace std;
int a[200010];
int n,x,q;
int main(){
cin >> n >> q;
// 输入有序数组
for(int i = 1; i <= n; i++) cin >> a[i];
while(q--){
cin >> x;
// lower_bound 找第一个 >= x 的位置
// 返回的是地址,减去 a 之后就是下标
cout << lower_bound(a + 1, a + n + 1, x) - a << endl;
}
return 0;
}
4. STL upper_bound:第一个 > x
思路简介
upper_bound 的含义是:
找第一个大于 x 的位置
写法:
upper_bound(a + 1, a + n + 1, x)
返回的是地址。
转成下标:
upper_bound(a + 1, a + n + 1, x) - a
带注释代码
#include<bits/stdc++.h>
using namespace std;
int a[200010];
int n,x,q;
int main(){
cin >> n >> q;
// 输入有序数组
for(int i = 1; i <= n; i++) cin >> a[i];
while(q--){
cin >> x;
// upper_bound 找第一个 > x 的位置
// 返回的是地址,减去 a 之后就是下标
cout << upper_bound(a + 1, a + n + 1, x) - a << endl;
}
return 0;
}
5. 手写 upper_bound:查找第一个 > x 的位置
思路简介
要找的是第一个满足:
a[i] > x
的位置。
二分时,如果:
a[mid] > x
说明 mid 可能是答案,但是前面可能还有更靠左的答案,所以:
ans = mid;
r = mid - 1;
如果:
a[mid] <= x
说明 mid 和左边都不满足,只能往右找:
l = mid + 1;
如果不存在,输出 n + 1。
带注释代码
#include<bits/stdc++.h>
using namespace std;
int a[200010];
int n,x,q;
int main(){
cin >> n >> q;
// 输入有序数组
for(int i = 1; i <= n; i++) cin >> a[i];
while(q--){
cin >> x;
int l = 1, r = n;
// ans 表示第一个 > x 的位置
// 如果找不到,默认是 n + 1
int ans = n + 1;
while(l <= r){
int mid = (l + r) / 2;
if(a[mid] > x){
// a[mid] 已经满足 > x
// 先记录答案
ans = mid;
// 但题目要第一个位置,所以继续往左找
r = mid - 1;
}else{
// a[mid] <= x,说明 mid 和左边都不满足
// 只能往右找
l = mid + 1;
}
}
cout << ans << endl;
}
return 0;
}
总结口诀
lower_bound:第一个 >= x
upper_bound:第一个 > x
找第一个满足条件的位置:
满足条件时,记录 ans,然后 r = mid - 1
找不到时:
第一个位置类问题,一般输出 n + 1
这几份代码的前提都是:数组必须是有序的。如果题目没保证有序,需要先写:
sort(a + 1, a + n + 1);
出现次数2
#include<bits/stdc++.h>
using namespace std;
int a[1000005];
int main(){
int n;
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
}
sort(a + 1, a + n + 1);
int q;
cin >> q;
while(q--){
int x,y;
cin >> x >> y;
// 找第一个 >= x 的位置
int l = 1, r = n;
int ans = n + 1;
while(l <= r){
int mid = (l + r) / 2;
if(a[mid] >= x){
ans = mid;
r = mid - 1;
}else{
l = mid + 1;
}
}
// 找最后一个 <= y 的位置
int l1 = 1, r1 = n;
int ans1 = 0;
while(l1 <= r1){
int mid = (l1 + r1) / 2;
if(a[mid] <= y){
ans1 = mid;
l1 = mid + 1;
}else{
r1 = mid - 1;
}
}
// 如果区间内没有数
if(ans > ans1){
cout << 0 << endl;
}else{
cout << ans1 - ans + 1 << endl;
}
}
return 0;
}
保龄球
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
// 结构体:存储每个位置的瓶子数和原始位置编号
struct node {
int c; // 瓶子数
int id; // 原始位置编号,从 1 开始
} a[N];
int n, Q; // n:位置数,Q:查询次数
// 按瓶子数 c 升序排序
bool cmp(node x, node y) {
return x.c < y.c;
}
// 二分查找函数:在有序数组 a 的区间 [l, r] 中查找目标值 x
int BinarySearch(node a[], int l, int r, int x) {
while (l <= r) {
int mid = (l + r) / 2; // 计算中间位置
if (a[mid].c == x) {
return mid; // 找到目标值,返回索引
} else if (a[mid].c > x) {
r = mid - 1; // 目标值在左半区,调整右边界
} else {
l = mid + 1; // 目标值在右半区,调整左边界
}
}
return -1; // 未找到,返回 -1
}
int main() {
cin >> n;
// 输入处理:读取每个位置的瓶子数,并记录原始位置编号
for (int i = 1; i <= n; i++) {
cin >> a[i].c;
a[i].id = i;
}
// 按瓶子数升序排序
sort(a + 1, a + n + 1, cmp);
cin >> Q;
while (Q--) {
int m; // 目标瓶子数
cin >> m;
// 二分查找目标值 m 在排序数组中的位置
int pos = BinarySearch(a, 1, n, m);
if (pos == -1) {
cout << 0 << endl; // 未找到输出 0
} else {
cout << a[pos].id << endl; // 找到则输出原始位置编号
}
}
return 0;
}
出现次数1
#include<bits/stdc++.h>
using namespace std ;
int a[200010];
int n,x,q;
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+n+1);
cin>>q;
while(q--){
cin>>x;
int r = upper_bound(a+1,a+n+1,x)-a-1;//最后一个>=x的位置
int l = lower_bound(a+1,a+n+1,x)-a; //第一个>=x的位置
cout<<r-l+1<<endl;
}
return 0;
}
和为 0 的 4 个值
// 线索1 A_i+B_j+C_k+D_l == 0
// 线索2 数组长度 n = 1000
// 暴力 循环4次 n^4 = 10^12
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3+10;
int a[N],b[N],c[N],d[N];
int p[N*N],id1 = 0;
int q[N*N],id2 = 0;
int main(){
int n;
cin >> n;
for(int i=1;i<=n;i++)cin>>a[i]>>b[i]>>c[i]>>d[i];
//A_i+B_j
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
p[++id1] = a[i]+b[j];
q[++id2] = c[i]+d[j];
}
}
sort(q+1,q+id2+1);
long long ans = 0;
for(int i=1;i<=id1;i++){
int x = -p[i];
int l = lower_bound(q+1,q+id2+1,x) - a;
int r = upper_bound(q+1,q+id2+1,x) - a;
ans+=r-l;
}
cout<<ans;
return 0;
}
最后一个等于x的元素
#include <iostream>
using namespace std;
const int N = 2e5 + 10;
int a[N];
int main() {
int n, q, x;
cin >> n >> q;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
while (q--) {
cin >> x;
int ans=-1;
int l = 1,r = n;
while(l<=r){
int mid=(l+r)/2;
if(a[mid]<=x){//找最后一个等于 x位置
if(a[mid]==x) ans=mid;
l=mid+1;
}else{
r=mid-1;
}
}
cout<<ans<<endl;
}
return 0;
}
不同分的人数
#include<bits/stdc++.h>
using namespace std;
int a[100010];
int n,q;
int main(){
cin>>n>>q;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+n+1);
while(q--){
int x;
cin>>x;
int l = lower_bound(a+1,a+n+1,x)-a;
int r = upper_bound(a+1,a+n+1,x)-a;
cout<<n - (r-l)<<endl;
}
return 0;
}
学生信息查询
#include<bits/stdc++.h>
using namespace std;
struct stu{
string id;
string name;
int sex;
int age;
}a[100010];
bool cmp(stu a,stu b){
return a.id<b.id;
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i].id>>a[i].name>>a[i].sex>>a[i].age;
sort(a+1,a+n+1,cmp);
int q;
cin>>q;
while(q--){
string t;
cin>>t;
stu x;
x.id = t;
int idx = lower_bound(a+1,a+n+1,x,cmp) - a;
if(a[idx].id==t){
cout<<a[idx].id<<" "<<a[idx].name<<" "<<a[idx].sex<<" "<<a[idx].age<<endl;
}else cout<<"No Answer!"<<endl;
}
return 0;
}
A-B数对
// B = A-C
//枚举A 数组中A-C的数量 -> 出现次数
#include<bits/stdc++.h>
using namespace std;
int a[100010],n,C;
int main(){
cin>>n>>C;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+n+1);
long long ans = 0;
for(int i=1;i<=n;i++){
int B = a[i]-C;
int l = lower_bound(a+1,a+n+1,B)-a;
int r = upper_bound(a+1,a+n+1,B)-a;
ans+=r-l;
}
cout<<ans;
return 0;
}
递增三元组
#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
long long a[N], b[N], c[N];
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
}
for(int i = 1; i <= n; i++){
cin >> b[i];
}
for(int i = 1; i <= n; i++){
cin >> c[i];
}
sort(a + 1, a + n + 1);
sort(c + 1, c + n + 1);
long long ans = 0;
for(int i = 1; i <= n; i++){
// A 中小于 b[i] 的数量
long long x = lower_bound(a + 1, a + n + 1, b[i]) - a - 1;
// C 中大于 b[i] 的数量
long long y = n - (upper_bound(c + 1, c + n + 1, b[i]) - c) + 1;
ans += x * y;
}
cout << ans << '\n';
return 0;
}
放学人潮
#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
struct node{
long long x; // 位置
char op; // 方向,'0' 往左,'1' 往右
}a[N];
long long b[N]; // 存所有往右走的人的位置
int cnt = 0;
bool cmp(node a,node b){
return a.x < b.x;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
long long T;
cin >> n >> T;
string s;
cin >> s;
for(int i = 1;i <= n;i++){
cin >> a[i].x;
a[i].op = s[i - 1];
}
// 按位置从小到大排序
sort(a + 1,a + n + 1,cmp);
// 把所有往右走的学生位置存到静态数组 b 中
for(int i = 1;i <= n;i++){
if(a[i].op == '1'){
b[++cnt] = a[i].x;
}
}
long long ans = 0;
// 枚举每一个往左走的人
for(int i = 1;i <= n;i++){
if(a[i].op == '0'){
/*
当前人位置为 a[i].x,往左走。
能和他擦肩而过的人必须:
1. 往右走
2. 在他的左边
3. 距离不超过 2*T
所以要统计 b 中有多少位置在:
[a[i].x - 2*T, a[i].x)
*/
long long L = a[i].x - 2 * T;
long long R = a[i].x;
int l = lower_bound(b + 1,b + cnt + 1,L) - b;
int r = lower_bound(b + 1,b + cnt + 1,R) - b;
ans += r - l;
}
}
cout << ans << '\n';
return 0;
}
全部评论 108
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
4小时前 来自 广东
1给
4小时前 来自 广东
0
1
9小时前 来自 广东
11
9小时前 来自 广东
11
9小时前 来自 广东
1能不能给老师上榜一
9小时前 来自 广东
11
6小时前 来自 广东
0
1
9小时前 来自 广东
11
9小时前 来自 广东
11
9小时前 来自 广东
11
9小时前 来自 广东
11
10小时前 来自 广东
11
9小时前 来自 广东
11
9小时前 来自 广东
1
1
10小时前 来自 广东
11
10小时前 来自 广东
1
1
10小时前 来自 广东
11
10小时前 来自 广东
11
10小时前 来自 广东
11
10小时前 来自 广东
11
10小时前 来自 广东
11
10小时前 来自 广东
1能不能不要拿AI生成这种基础的东西了……
能不能不要疯狂顶这种帖子了……2小时前 来自 上海
0这是什么题目
2小时前 来自 浙江
01
3小时前 来自 广东
0





























有帮助,赞一个