题目概述
题目描述
在运动会上,小明从数轴的原点开始向正方向立定跳远。项目设置了 n 个检查点 a1, a2, . . . , an 且 ai ≥ ai−1 > 0。小明必须先后跳跃到每个检查点上且只能跳跃到检查点上。同时,小明可以自行再增加 m 个检查点让自己跳得更轻松。
在运动会前,小明制定训练计划让自己单次跳跃的最远距离达到 L,并且学会一个爆发技能可以在运动会时使用一次,使用时可以在该次跳跃时的最远距离变为 2L。小明想知道,L 的最小值是多少可以完成这个项目?
输入格式
输入共 2 行。
第一行为两个正整数 n, m。
第二行为 n 个由空格分开的正整数 a1, a2, . . . , an。
输出格式
输出共 1 行,一个整数表示答案。
样例输入
复制
5 3 1 3 5 16 21
样例输出
复制
3
提示
【样例说明】
增加检查点 10, 13, 19,因此每次跳跃距离为 2, 2, 5, 3, 3, 3, 2,在第三次跳跃时使用技能即可。
【评测用例规模与约定】
对于 20% 的评测用例,保证 n ≤ 102,m ≤ 103,ai ≤ 103。
对于 100% 的评测用例,保证 2 ≤ n ≤ 105,m ≤ 108,0 < ai ≤ 108。
解题思路
首先我们观察到添加检查点我们的跳的最远距离必定减少具有单调性,题目还说可以使用一次技能使用时可以在该次跳跃时的最远距离变为 2L,使用技能时相当于跳了两次,可以想到把这个技能转换成多加一个检查点(我当时打比赛时没有想到QAQ),这个代码很好写的
代码
#include<iostream>
#define int long long
using namespace std;
const int N=1e5+5;
int a[N];
int n,m;
int check(int x)
{
int ans=0;
for(int i=1;i<=n;i++)
{
if(a[i]-a[i-1]>=x)//判断两个检查之间还要加几个检查点使得跳的最远距离为X
if((a[i]-a[i-1])%x==0)
ans+=(a[i]-a[i-1])/x-1;
else
ans+=(a[i]-a[i-1])/x;
}
if(ans<=m+1)//如果加的检查点多了说明跳的最长距离短了返回1 (这里跟m+1进行比较我前面也提了把一次技能转换成了多加一个检查点)
return 1;
else
return 0;
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
int l=0,r=1e8;
while(l<r)
{
int mid=l+r>>1;
if(check(mid))
r=mid;
else
l=mid+1;
}
cout<<l;
return 0;
}