二分练习11

蓝桥账户中心分巧克力

#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 = 0r = 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 表示不满足条件):

边长012345
条件TTTFFF

二分查找过程如下:

  1. 初始 l = 0r = 6mid = (0 + 6) / 2 = 3check(3) 为 false,则 r = 3,区间变为 [0, 3)
  2. 此时 mid = (0 + 3) / 2 = 1check(1) 为 true,则 l = 1 + 1 = 2,区间变为 [2, 3)
  3. 此时 mid = (2 + 3) / 2 = 2check(2) 为 true,则 l = 2 + 1 = 3,区间变为 [3, 3),查找结束。

最终 l = 3,正好指向第一个不满足条件的边长。

所以,基于上述二分查找的逻辑和区间更新规则,l 最终指向的是第一个不满足条件的边长。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值