这本质上是一个在路径上插入点,使相邻点距离不超过跳跃能力的问题。
我们可以把问题想象成:
-
在数轴[0, aₙ]上有一条路径
-
必须经过所有原始检查点
-
可以在任意位置添加额外点
-
相邻点距离 ≤ L(普通跳跃)或 ≤ 2L(使用技能的那次)
check函数:
对于给定的L,我们需要判断:
在最多添加m个额外点,且最多使用一次技能的情况下,能否从0跳到aₙ,并经过所有原始检查点?
cpp
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=100010;
int n,m;
ll a[N];
bool check(ll l)
{
ll cur=0;
ll need=0;
//计算不使用技能需要的额外点
for(int i=0;i<n;i++)
{
ll dist=a[i]-cur;
if(dist>l)
{
need+=(dist+l-1)/l-1;
}
cur=a[i];
}
if(need<=m)return true;
//计算使用技能最多能省多少点
ll max_save=0;
cur=0;
for(int i=0;i<n;i++)
{
ll dist=a[i]-cur;
ll normal_need=max(0LL,(dist+l-1)/l-1);
ll skill_need=max(0LL,(dist+2*l-1)/(2*l)-1);
ll save=normal_need-skill_need;
max_save=max(max_save,save);
cur=a[i];
}
return (need-max_save)<=m;
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)cin>>a[i];
int left=1,right=a[n-1];
while(left<right)
{
int mid=(left+right)>>1;
if(check(mid))right=mid;
else left=mid+1;
}
cout<<left<<endl;
return 0;
}