秒懂百科,C++如此简单丨第二十二天:二分答案
爱编程的小芒果 2024-08-10 13:05:03 阅读 51
前言
秒懂百科,C++如此简单系列终于更新啦!
Everyday English
Yesterday is history, tomorrow is a mystery, but today is a gift.
昨天是历史,明天是个谜,今天是礼物。把握好当下。
二分查找和二分答案
一看到标题是二分是不是就感觉以前学过,的确在第十一天时,我们就已经学过了。网址:秒懂百科,C++如此简单丨第十一天:二分查找-CSDN博客
但是,你仔细一读标题会发现,我们今天学的是二分答案。
那他俩有啥区别呢,顾名思义。二分查找是去找一个数,而二分答案是去二分某一题的答案,直至满足题目所问。
但是不管怎样,都有可能会用到以下程序:
<code>while(l<=r)
{
mid=(l+r)/2;
if()
{
l=mid+1;
}
else
{
r=mid-1;
}
}
为什么说有可能呢?我们来看一道题目。
洛谷 P3881 栓奶牛
网址:[信息与未来 2015] 拴奶牛 - 洛谷
理解问题
这题目一出来,你是不是看得云里雾里?有两个地方很绕,我们来一起看一看。
1.Pi = Pi-1 + ((Pi-1 x 2357 + 137) mod 10) + 1
这个其实是k个木桩位置的生成方式。你不要管数字有多么大,你只要按照说的做就行了。
因为已经给出P1了,那么从P2开始,带入这个式子,就可以依次算出来所有木桩的位置了。
2.最近距离的最大值
不要被最近和最大绕进去了。我来问问你,如果相隔距离为100可以实现,那么距离为1是不是也能实现?也就是说小的都能实现,但我们要求出其中最大的。
思路点拨
我们可以写一个二分答案的程序,如果这个答案能满足条件,我们就先记录下来,但是我们想要答案尽可能的大,我们得让左指针移动到mid+1。
否则,让右指针移动到mid-1,说明我们答案太大了,满足不了条件。
那我们怎么写检查答案是否满足这个条件呢?
其实很简单,你这要用mid照着题目意思模拟即可。
当遇到一个木桩,用sum+当前木桩与前一个木桩的差值。一但sum>=mid,就让计数器+1,sum=0。
最后看一眼计数器是否能栓题目所给的数量(大于等于都可以)
AC代码
<code>#include<bits/stdc++.h>
using namespace std;
long long n,k,k1,a[10000000];
bool check(long long mid)
{
long long kk=1;//kk为计数器,注意第一头奶牛已经默认栓在第一个木桩
long long sum=0;
for(long long i=1;i<=k;i++)
{
sum+=a[i+1]-a[i];//加上差值
if(sum>=mid)//如果>=mid的值,这里mid是两头牛之间的距离
{
kk++;
sum=0;
}
}
if(kk>=n) return 1;
else return 0;
}
int main()
{
cin>>n>>k>>k1;
a[1]=k1;
for(long long i=2;i<=k;i++)
{
a[i]=a[i-1]+((a[i-1]*2357+137)%10)+1;//照着式子带入
}
long long l=1,r=a[k],mi,t;//l最小是1,r最大是最后一个木桩的坐标
while(l<=r)
{
mi=(l+r)/2;//二分答案
if(check(mi))//如果满足题目
{
t=mi;//先记录一下答案
l=mi+1;//看看还有没有更大的
}
else
{
r=mi-1;//数字太大了,满足不了
}
}
cout<<t<<endl;
return 0;
}
扩展补充
既然有最小值中的最大值,那么有没有最大值中的最小值呢?答案是肯定的!
代码整体思路是一样的,但要注意如果满足条件应该找一找有没有更小的答案。
所以说满足条件时,r=mid-1。否则l=mid+1,数字太小了,满足不了条件。
总结
今天我们一起学习了二分答案,给你详细讲了一道题目。不知道你有没有收获呢?
如果觉得本篇文章还不错的话,希望你能送上手中点赞、收藏和评论,这对我来说很重要。
我是爱编程的小芒果,我们下篇再见!Bye~
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。