做到一连两个题都是用到了这种模板 方法
第一个 切绳子
第二个 月度开销
我是先做的第一个然后去写了第二个,(这种思路我想不到…苦涩)然后发现这两道题有很像的地方(可能因为都是二分的题目),接下来是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就是所要找的的不大不小的正确答案了。
不要觉得这个方法只在这道题里有用(看懂了记下来真的很有用!!)来自卑微蒟蒻的最后一点挣扎,我觉得可以用在很多地方可能只是还没碰到这种题,反正记着就完事儿了√
(侵删致歉)