2024蓝桥杯省赛保奖突击班-Day1-二分查找_笔记_练习题解

3月22日-课堂笔记

  • 非降序序列二分查找等于 x x x 的数下标
cpp 复制代码
int find(int x, int l, int r) {
	while(l < r) {
		int mid = (l + r) / 2;
		if(x <= a[mid]) r = mid;
		else l = mid + 1;
	}
	return l;
}
  • 非降序可重序列下标最小 ≥ x \geq x ≥x 的元素
cpp 复制代码
int find(int x, int l, int r) {
	while(l < r) {
		int mid = (l + r) / 2;
		if(a[mid] >= x) r = mid;
		else l = mid + 1;
	}
	return l;
}
  • C++ STL 的使用
cpp 复制代码
vector<int> a(n);
int id = lower_bound(a.begin(), a.end(), x) - a.begin();
int id = upper_bound(a.begin(), a.end(), x) - a.begin();
int a[N];
int id = lower_bound(a + 1, a + n + 1, x) - a;
int id = upper_bound(a + 1, a + n + 1, x) - a;
  • a中元素 x x x 出现的次数 O ( log ⁡ n ) \mathcal{O}(\log n) O(logn)
cpp 复制代码
int count = upper_bound(a.begin(),a.end(),x) -- lower_bound(a.begin(),a.end(),x);

练习题解

P1102 A-B 数对

题目链接:P1102
参考思路

对于给定的 A − B = C A-B=C A−B=C,其中 C C C已知,那么我们可以枚举 A A A二分查找 B B B的范围,其中

C++参考代码
cpp 复制代码
//用系统库函数
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int a[N];
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	int n, C;
	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 L = lower_bound(a + 1, a + n + 1, a[i] - C) - a;
		int R = upper_bound(a + 1, a + n + 1, a[i] - C) - a - 1;
		ans += R - L + 1;
	}
	cout << ans << endl;
	return 0;
}
cpp 复制代码
//方便大家理解手动实现了一下函数
#include <bits/stdc++.h>

using namespace std;

int lowerBound(const vector<int>& a, int key) {
    int low = 0, high = a.size();
    while (low < high) {
        int mid = (low + high) / 2;
        if (a[mid] < key) {
            low = mid + 1;
        } else {
            high = mid;
        }
    }
    return low;
}

int upperBound(const vector<int>& a, int key) {
    int low = 0, high = a.size();
    while (low < high) {
        int mid = (low + high) / 2;
        if (a[mid] <= key) {
            low = mid + 1;
        } else {
            high = mid;
        }
    }
    return low;
}

int main() {
    int n, C;
    cin >> n >> C;

    vector<int> a(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }
    sort(a.begin(), a.end());

    long long ans = 0;
    for (int i = 0; i < n; ++i) {
        int L = lowerBound(a, a[i] - C);
        int R = upperBound(a, a[i] - C);
        ans += R - L;
    }

    cout << ans << endl;

    return 0;
}
Java参考代码
java 复制代码
import java.util.*;
public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n, C;
        n = scanner.nextInt();
        C = scanner.nextInt();

        int[] a = new int[n];
        for (int i = 0; i < n; ++i) {
            a[i] = scanner.nextInt();
        }
        Arrays.sort(a);

        long ans = 0;
        for (int i = 0; i < n; ++i) {
            int L = lowerBound(a, a[i] - C);
            int R = upperBound(a, a[i] - C);
            ans += R - L;
        }

        System.out.println(ans);
        scanner.close();
    }
    static int lowerBound(int[] a, int key) {
        int low = 0;
        int high = a.length;
        while (low < high) {
            int mid = (low + high) / 2;
            if (a[mid] < key) {
                low = mid + 1;
            } else {
                high = mid;
            }
        }
        return low;
    }
    static int upperBound(int[] a, int key) {
        int low = 0;
        int high = a.length;
        while (low < high) {
            int mid = (low + high) / 2;
            if (a[mid] <= key) {
                low = mid + 1;
            } else {
                high = mid;
            }
        }
        return low;
    }
}
Python参考代码
py 复制代码
def lower_bound(a, key):
    low, high = 0, len(a)
    while low < high:
        mid = (low + high) // 2
        if a[mid] < key:
            low = mid + 1
        else:
            high = mid
    return low

def upper_bound(a, key):
    low, high = 0, len(a)
    while low < high:
        mid = (low + high) // 2
        if a[mid] <= key:
            low = mid + 1
        else:
            high = mid
    return low

def main():
    n, C = map(int, input().split())
    a = list(map(int, input().split()))
    
    a.sort()

    ans = 0
    for i in range(n):
        L = lower_bound(a, a[i] - C)
        R = upper_bound(a, a[i] - C)
        ans += R - L

    print(ans)

if __name__ == "__main__":
    main()

P1678 烦恼的高考志愿

题目链接:P1678
参考思路
  • 题目意思其实就是求某一个学生和某一个分数线最小的差的绝对值,求和。
  • 那么我们先对学校分数线 a a a数组排序,然后对于每一个学生 b i b_i bi去学校分数也就是 a a a数组中二分查找学生分数 b i b_i bi左右两边最近的数即:最后一个小于等于 b i b_i bi的数和第一个大于等于 b i b_i bi的数。
  • 特别注意特殊处理当所有的分数都高于或者低于学生分数的情况。
C++参考代码
cpp 复制代码
#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 10;
int a[N], b[N];
int findr(int t, int l, int r) {

    while (l < r) {
        int mid = (l + r) / 2;
        if (t <= a[mid]) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }
    return l;
}

int findl(int t,int l, int r) {

    while (l < r) {
        int mid = (l + r + 1) / 2;
        if (t >= a[mid]) {
            l = mid;
        } else {
            r = mid - 1;
        }
    }
    return l;
}
int main() {

    int m, n;
    cin >> m >> n;
    for (int i = 0; i < m; i++)
        cin >> a[i];

    for (int i = 0; i < n; i++)
        cin >> b[i];

    sort(a, a + m);

    long long res = 0;
    for (int i = 0; i < n; i++) {
        if (b[i] <= a[0])
            res += abs(b[i] - a[0]);
        else if (b[i] >= a[m - 1])
            res += abs(b[i] - a[m - 1]);
        else {
            int l = a[findr(b[i], 0, m)];
            int r = a[findl(b[i], 0, m)];
            int ls = abs(l - b[i]);
            int rs = abs(r - b[i]);
            if (ls < rs) {
                res += ls;
            } else {
                res += rs;
            }
        }
    }
    cout << res << endl;
    return 0;
}
Java参考代码
java 复制代码
import java.util.*;

public class Main {
    static int[] a = new int[100010];
    static int[] b = new int[100010];

    static int findr(int t, int l, int r) {
        while (l < r) {
            int mid = (l + r) / 2;
            if (t <= a[mid]) {
                r = mid;
            } else {
                l = mid + 1;
            }
        }
        return l;
    }

    static int findl(int t, int l, int r) {
        while (l < r) {
            int mid = (l + r + 1) / 2;
            if (t >= a[mid]) {
                l = mid;
            } else {
                r = mid - 1;
            }
        }
        return l;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int m = scanner.nextInt();
        int n = scanner.nextInt();
        for (int i = 0; i < m; i++)
            a[i] = scanner.nextInt();
        for (int i = 0; i < n; i++)
            b[i] = scanner.nextInt();

        Arrays.sort(a, 0, m);

        long res = 0;
        for (int i = 0; i < n; i++) {
            if (b[i] <= a[0])
                res += Math.abs(b[i] - a[0]);
            else if (b[i] >= a[m - 1])
                res += Math.abs(b[i] - a[m - 1]);
            else {
                int l = a[findr(b[i], 0, m)];
                int r = a[findl(b[i], 0, m - 1)];
                int ls = Math.abs(l - b[i]);
                int rs = Math.abs(r - b[i]);
                if (ls < rs) {
                    res += ls;
                } else {
                    res += rs;
                }
            }
        }
        System.out.println(res);
    }
}
Python参考代码
py 复制代码
def findr(t, l, r):
    while l < r:
        mid = (l + r) // 2
        if t <= a[mid]:
            r = mid
        else:
            l = mid + 1
    return l

def findl(t, l, r):
    while l < r:
        mid = (l + r + 1) // 2
        if t >= a[mid]:
            l = mid
        else:
            r = mid - 1
    return l

m, n = map(int, input().split())
a = list(map(int,input().split()))
b = list(map(int,input().split()))

a.sort()

res = 0
for i in range(n):
    if b[i] <= a[0]:
        res += abs(b[i] - a[0])
    elif b[i] >= a[m - 1]:
        res += abs(b[i] - a[m - 1])
    else:
        l = a[findr(b[i], 0, m)]
        r = a[findl(b[i], 0, m - 1)]
        ls = abs(l - b[i])
        rs = abs(r - b[i])
        if ls < rs:
            res += ls
        else:
            res += rs

print(res)

P1918 保龄球

题目链接:P1918
思路:其实就是找这个数存在的位置,不存在输出0,可以用map记录位置也可以二分查找,大家可以参考:官方题解
相关推荐
青い月の魔女22 分钟前
数据结构初阶---二叉树
c语言·数据结构·笔记·学习·算法
qq_5895681030 分钟前
node.js web框架koa的使用
笔记·信息可视化·echarts
stm 学习ing1 小时前
HDLBits训练6
经验分享·笔记·fpga开发·fpga·eda·verilog hdl·vhdl
柒月的猫2 小时前
方格分割(蓝桥杯2017年试题D)
职场和发展·蓝桥杯
stm 学习ing2 小时前
HDLBits训练4
经验分享·笔记·fpga开发·课程设计·fpga·eda·verilog hdl
炸毛的飞鼠2 小时前
汇编语言学习
笔记·学习
风无雨2 小时前
react杂乱笔记(一)
前端·笔记·react.js
胡西风_foxww2 小时前
【ES6复习笔记】Class类(15)
javascript·笔记·es6·继承··class·静态成员
2301_815389373 小时前
【笔记】下载mysql5.7
笔记
柒月的猫4 小时前
翻转(蓝桥杯2023大学C组试题E)
职场和发展·蓝桥杯