洛谷P8647 [蓝桥杯 2017 省 AB] 分巧克力题解(附二分模板讲解)

这道题充分考察了二分的灵活使用,但是二分有两个常用模板,在讲解之前可以先复习一下二分的两个模板

寻找大于等于某一个目标数字的最小下标:

int l = 0,r = n - 1;//num为要查找的目标数字,l为下边界,r为上边界,n为数组长度
while ( l < r ){
    int mid = ( l + r ) >> 1;//用位运算计算比除以二要快,也是一个技巧
    //if ( a [mid] >= num )
    if ( check ( mid ) ) r = mid;//这个是通用写法
    else l = mid + 1;
}
cout << l << endl;

这个还是很好理解时,当中间数据大于查找数字时,说明我们要查找的数字有可能就是这个数字或者在这个数字下面,所以让r = mid ,否则就让 l = mid +1

寻找小于等于某一个目标数字的最大下标:

int l = 0,r = n - 1;
while ( l < r ){
    int mid = ( l + r +1 ) >> 1;
    //if ( a [mid] <= num )
    if ( check ( mid ) )l=mid;
    else r = mid -1;
}
cout << r << endl;

这里为什么要对mid 计算时加一呢,我们不妨先考虑一种极端情况,我们要查找的数字是2,目标数组是

a[ ]={2,2};请看图片

因此我们要在计算mid时加一,保证中间值偏移,从而达到查找目的。

好的,那么现在看这道题,我们如何使用二分知识解决此题呢?

首先我们知道,每个小孩获得的巧克力是一样的,所以我们可以计算每一个边长下可以切分的巧克力数量,再与孩子数量做比较即可,那么每次选择的边长可以用二分查找,而每一块巧克力可以切分的目标大小巧克力数量就是(n/r)* (m/r) n、m分别为当前巧克力的长度,宽度

话不多说,上代码:

#include
using namespace std;

typedef long long LL;
const int N = 100010;
int a[N],b[N];
int n,k;

bool check(int mid){
    LL ans=0;
    for(int i=0;i=k)return true;
    else return false;
}

int main(){
    cin>>n>>k;
    
    int ans=0;
    for(int i=0;i>1;
        if(check(mid))l=mid+1;//通用二分模板
        else r=mid; 
    }
    printf("%d",l-1);//这里为什么要输出l-1呢,因为我们进行了l+1操作时,l才是目标答案
    
    return 0;
}

为什么我没有在设置上边界时直接将r设为N呢, 因为刚开始我就是那样做的,结果TLE了

当然,用第二个二分模板也是可以做的,小伙伴们可以自己试一下

最后,码字不易,希望给一个免费的赞,谢谢!

你可能感兴趣的:(算法)