二分学习记录

手写实现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;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值