这道题的难度不大,但是确实是一个练习二分的好题;
先说一下我的心路历程吧,很惭愧,本菜的第一个思路居然是贪心,步骤是这样的;
(1)先处理数据,得到每个区间的长度;
(2)进行k次循环,每次循环找到最长区间,然后将这个区间分成俩半;
很不显然,这个是错误的,直到我自己测试了只有两个路标,且分别在端点,路的长度为1000,且可以插入100个路标;
很显然,上面的正确答案应该是10,但是通过上面的贪心得到的确实16,所以通过一个例子就推翻了这个思路,然后我开始想另外的思路,即二分;
这里我们就很容易得到答案了,每次check(l+r>>1),check函数是这样的:
记l+r>>1为d,且num为可以插入的路标个数,len[N]中存储每一个区间的长度
(1)循环每一个长度,看是否大于d;
1:如果大于d,则
2:否则跳过
(2)遍历完成后看num是否<0
1:num<0成立,返回l=l+r>>1+1;
2:不成立r=l+r>>1;
然后输出r即可;
下面是代码
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
const int N=100010;
int l1,n,k;
int st[N];
int len[N];
bool check(int d){
int num=k;
for(int i=1;i<n;i++){
if(len[i]>d) num-=len[i]/d-((len[i]%d)==0);
}
if(num<0) return 0;
return 1;
}
int main(){
cin>>l1>>n>>k;
for(int i=0;i<n;i++){
cin>>st[i];
}
for(int i=1;i<n;i++)
len[i]=st[i]-st[i-1];
int l=0,r=l1;
while(l<r){
int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
cout<<r;
}