蓝桥账户中心分巧克力
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,k;
int h[N],w[N];
int mx=90000000;
bool check(int mid)
{
int res=0;
for(int i=0;i<n;i++){
res+=(h[i]/mid)*(w[i]/mid);
if(res>=k) return true;
}
return false;
}
int main()
{
// 请在此输入您的代码
ios::sync_with_stdio(false);cin.tie(0);
cin >> n >> k;
for(int i=0;i<n;i++){
cin >> h[i] >> w[i];
}
int l=1,r=N;
while(l<r)
{
int mid=l+r>>1;
if(check(mid)) l=mid+1;
else r=mid;
}
cout << l-1;
return 0;
}
为什么输出l-1
在这段代码中使用二分查找来确定能切出至少 k
块正方形巧克力的最大边长,最终输出 l - 1
,这和二分查找的具体实现以及查找目标有关,下面详细解释:
二分查找的目标与区间划分
二分查找的目标是在一个有序区间 [0, maxn + 1]
内找到满足条件(能切出至少 k
块正方形巧克力)的最大边长。
在二分查找过程中,对于中间值 mid
,通过 check(mid)
函数判断以边长 mid
能否从所有巧克力中切出至少 k
块正方形巧克力:
- 如果
check(mid)
为true
,说明边长mid
是满足条件的,我们要找的最大边长可能更大,所以将左边界l
更新为mid + 1
,继续在右半区间查找更大的可能边长。 - 如果
check(mid)
为false
,说明边长mid
不满足条件,我们要找的最大边长一定小于mid
,所以将右边界r
更新为mid
,继续在左半区间查找。
二分查找结束时 l
的含义
当二分查找结束(l >= r
)时,l
指向的是第一个不满足条件的边长。
这是因为在二分查找过程中,每次找到一个满足条件的 mid
时,都会将 l
更新为 mid + 1
,不断向右推进,直到找到第一个不满足条件的位置。
输出 l - 1
的原因
由于 l
指向的是第一个不满足条件的边长,那么 l - 1
就是最后一个满足条件的边长,也就是我们要找的能切出至少 k
块正方形巧克力的最大边长。
示例说明
假设巧克力的边长范围是 [0, 10]
,经过二分查找,最终 l
指向 6
,这意味着边长为 6
时不能切出至少 k
块正方形巧克力,而在二分查找过程中已经知道边长为 5
时是满足条件的,所以最大边长就是 l - 1 = 5
。
综上所述,输出 l - 1
是为了得到满足条件的最大边长。
为什么l 指向的是第一个不满足条件的边长
这和代码中二分查找的实现逻辑以及边界更新规则紧密相关。下面详细解释为何在这段代码里 l
最终指向的是第一个不满足条件的边长。
二分查找基本逻辑
二分查找的核心在于不断将搜索区间一分为二,依据中间元素是否满足特定条件,来决定是在左半区间还是右半区间继续查找,从而缩小搜索范围,直至找到目标元素或者确定目标元素不存在。
代码中的二分查找实现
收起
cpp
int l = 0, r = maxn + 1, mid;
while (l < r) {
mid = (l + r) >> 1;
if (check(mid)) l = mid + 1;
else r = mid;
}
- 初始区间:设定搜索区间为
[l, r)
,这里l = 0
,r = maxn + 1
,也就是从边长0
开始,到最大可能边长maxn + 1
进行查找。注意这里是左闭右开区间。 - 中间值计算:每次计算中间值
mid = (l + r) >> 1
,等同于(l + r) / 2
。 - 条件判断与区间更新:
- 若
check(mid)
为true
:意味着边长mid
满足能切出至少k
块正方形巧克力的条件。因为我们要找的是最大边长,所以可能存在更大的满足条件的边长,于是把左边界l
更新为mid + 1
,这样就将搜索范围缩小到右半区间[mid + 1, r)
。 - 若
check(mid)
为false
:表明边长mid
不满足条件,最大边长必然小于mid
,所以把右边界r
更新为mid
,将搜索范围缩小到左半区间[l, mid)
。
- 若
二分查找结束时 l
的位置
- 二分查找的终止条件是
l >= r
,在这个代码里,由于采用的是左闭右开区间[l, r)
,当l == r
时查找结束。 - 在每次迭代中,只要
mid
满足条件,l
就会不断向右移动(更新为mid + 1
)。这就保证了l
左侧的所有边长都是满足条件的。 - 当
mid
不满足条件时,r
会更新为mid
,使得不满足条件的部分被排除在搜索区间右侧。 - 最终,当查找结束时,
l
会停在第一个不满足条件的边长位置。这是因为在查找过程中,满足条件的边长都被 “挤” 到了l
的左侧,而l
本身对应的边长是第一个不满足条件的。
示例说明
假设搜索区间是 [0, 5]
,对应的满足条件的情况如下(T
表示满足条件,F
表示不满足条件):
边长 | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
条件 | T | T | T | F | F | F |
二分查找过程如下:
- 初始
l = 0
,r = 6
,mid = (0 + 6) / 2 = 3
,check(3)
为false
,则r = 3
,区间变为[0, 3)
。 - 此时
mid = (0 + 3) / 2 = 1
,check(1)
为true
,则l = 1 + 1 = 2
,区间变为[2, 3)
。 - 此时
mid = (2 + 3) / 2 = 2
,check(2)
为true
,则l = 2 + 1 = 3
,区间变为[3, 3)
,查找结束。
最终 l = 3
,正好指向第一个不满足条件的边长。
所以,基于上述二分查找的逻辑和区间更新规则,l
最终指向的是第一个不满足条件的边长。