手写实现lower_bound(即返回数组中第一个大于等于该数的下标)
int Lower_bound( int l, int r, int target)
{
//lower_bound函数实现的是查询数组中第一个大于或等于target数字的下标
while (l <= r) {
int mid = (l + r) / 2;
if (arr[mid] < target) l = mid + 1;
else r = mid - 1;
}
if(arr[l]==target)return l;
else return -1;
//要是输入一个比当前数组中数都要小的数 会返回1
}
手写实现upper_pound
(upper_bound函数是查询数组中第一个大于target数字的下标)
int Upper_bound(int l, int r, int target)
{
while (l <= r) {//当l到r+1或者r=l-1时退出
int mid = (l + r) / 2;
if (arr[mid] <= target) l = mid + 1;
else r = mid - 1;
}
if (arr[l] < target)return -1;//找不到就是输出-1
else return l;//找得到的话正常输出
//如果输入一个比数组内任何数都小的数 那么返回即是1
}
搜索右边界(即数组中出现连续相同的元素时,输出该元素最右边的下标)
eg:arr[6]={0,1,2,2,2,3}这时候查询2,输出的下标编号是4
int right_bound(int l, int r, int target) {
while (l <= r) {
int mid = l + (r - l) / 2;//不知道为啥 这样比较稳定
if (arr[mid] <= target)l = mid + 1;
else r = mid - 1;//其他写法就跟上两种函数差不多
}
if (r < 0 || arr[r] != target)return -1;
else return r;//这里注意 是返回r
}
来道洛谷例题P2249 【深基13.例1】查找 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P2249
P2249 【深基13.例1】查找
题目描述
输入 n(n≤106) 个不超过 10^9 的单调不减的(就是后面的数字不小于前面的数字)非负整数 a_{n}a1,a2,…,an,然后进行 m(m≤105) 次询问。对于每次询问,给出一个整数 q(q≤109),要求输出这个数字在序列中第一次出现的编号,如果没有找到的话输出 -1 。
输入格式
第一行 2 个整数 n 和 m,表示数字个数和询问次数。
第二行 n 个整数,表示这些待查询的数字。
第三行 m 个整数,表示询问这些数字的编号,从 1 开始编号。
输出格式
m 个整数表示答案。
输入输出样例
输入 #1复制
11 3 1 3 3 3 5 7 9 11 13 15 15 1 3 6
输出 #1复制
1 2 -1
很基础的模板二分题,考察的内容是左边界二分,拿着我上面的lower_bound代码快去把这道题a了吧
………………………………………………………………………………………………
再来一道题
P2440 木材加工 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
P2440 木材加工
题目背景
要保护环境
题目描述
木材厂有 n 根原木,现在想把这些木头切割成 k 段长度均为 l 的小段木头(木头有可能有剩余)。
当然,我们希望得到的小段木头越长越好,请求出 l 的最大值。
木头长度的单位是 cm,原木的长度都是正整数,我们要求切割得到的小段木头的长度也是正整数。
例如有两根原木长度分别为 11 和 21,要求切割成等长的 6 段,很明显能切割出来的小段木头长度最长为 5。
输入格式
第一行是两个正整数 n,k,分别表示原木的数量,需要得到的小段的数量。
接下来 n 行,每行一个正整数 Li,表示一根原木的长度。
输出格式
仅一行,即 ll 的最大值。
如果连1cm 长的小段都切不出来,输出 0
。
输入输出样例
输入 #1复制
3 7 232 124 456
输出 #1复制
114
说明/提示
数据规模与约定
对于 100\%100% 的数据,有 1≤n≤105,1≤k≤108,1≤Li≤108(i∈[1,n])。
代码:
#include<iostream>
using namespace std;
typedef long long int ll;
ll n, k, l, r, sum, mid;//ans是所有木头能切出的木头数
int arr[23300000];
bool check(ll x) {//check函数实现的是找以当前单根木头长度来分
//对于每根原木能切出多少小根
//如果小根的数量大于或等于需要的小根数量 说明还能切得更长
ll ans = 0;
for (int i = 1; i <= n; i++)ans += arr[i] / x;
return ans >= k;
}
int main() {
cin >> n >> k;
for (int i = 1; i <= n; i++) cin >> arr[i], sum += arr[i];
l = 0, r = 100000001;//数据范围最高要求1e8所以右边界设置得高些
//二分右边界
while (l <= r) {
ll mid = l + (r - l) / 2;
if (mid == 0) {
r = 0; break;
}
if (check(mid))l = mid + 1;
else r = mid - 1;
}
cout << r;
return 0;
}