二分:一个非常重要的思想(或者说是解题模板)

做到一连两个题都是用到了这种模板 方法
第一个 切绳子
第二个 月度开销
我是先做的第一个然后去写了第二个,(这种思路我想不到…苦涩)然后发现这两道题有很像的地方(可能因为都是二分的题目),接下来是copy+write by myself(蒟蒻卑微)

作者: yizimi远欣(洛谷上p1577的第一个题解我觉得挺好的)点此进入
这里,我们不知道截成的k个小段每条有多长,却给出了k,也就是说我们可以先假设一个x为每段的长度,判断他是不是正确的、可行的。
判断可以用这种方法判断(假设已经输入了a[i],即所给的n条绳子):

int ans=0;
for(int i=1;i<=n;i++){
    ans+=a[i]/x;//直接向下取整,方便了计算,叠加了每一条绳子可以截出的和 
}

但是,你假设的x是不是正确的呢???显然可能性很小,可能你所能截的段数少,也可能多。如果一点一点加的话肯定很复杂说不定还会超时,所以这个时候就需要二分来解决了。

如果一个假设的x所计算出的个数不与题目所给的k段相同,那么就去分析一下这个x是小了还是大了。如果x小了,也就是说,可以截成的段数多了,所计算出的k’就大于k了,如果x大了,则相反。这样,我们就可以根据算出的k’的大小来调整x。
判断大小就可以直接改一下上面的代码:

inline int judge(int x){
    int ans=0;
    for(int i=1;i<=n;i++){
        ans+=a[i]/x;//直接向下取整,方便了计算,叠加了每一条绳子可以截出的和 
    }
    if(ans>=k)
        return true;//如果算出的k'大于等于k,则x小于等于正确答案,返回true
    else
        return false;//如果算出的k'小于k,则x大于正确答案,返回false 
}

二分的性质(伪)就是有一定的排列方式,这里,x相对于正确答案的大小就是这个排列方式。我们可以用一个二分来一次一次的寻找答案,直到左右界重合。这样的寻找答案的方式就是二分答案。
二分答案核心代码除了判断大小(如上),就是寻找答案的步骤了。这个代码比较死,大家记住就OK,绝大多数二分答案题可以使用:

int l=0,r=100000000;
//把左端与右端定义,这个地方有些题范围不能开太大,有一定的要求,不过这里就OK了
while(l<=r){
    int mid=(l+r)/2;
    if(judge(mid))//判断步骤 
        l=mid+1;
    else
        r=mid-1;//有些题这里有微调……不过不影响 
} 
cout<<r; 

直到while循环结束,r就是所要找的的不大不小的正确答案了。

不要觉得这个方法只在这道题里有用(看懂了记下来真的很有用!!)来自卑微蒟蒻的最后一点挣扎,我觉得可以用在很多地方可能只是还没碰到这种题,反正记着就完事儿了√
(侵删致歉)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值