题目链接
题意:
有只青蛙要跳过一条长L的河,其间有n块石头,最多可以跳m次,途中可以借助石头跳到对岸,也可以直接跳到对岸,给出石头距岸边的距离,青蛙每次跳都有一个跳跃距离,跳跃距离必须等于当前位置距要跳的石头或者是对岸的距离才能跳到那个位置,问青蛙在所有可行方案(能跳到对岸,且满足上述条件)中跳的最远的距离至少为多少。
条件:1<=L <= 1000000000,0<= n <= 500000,1<= m <= n+1
分析:
因为n为5*1e5,限时一秒,所以O(n^2)不适用,即纯模拟是无法通过的,而这题也是入门二分题,复杂度O(nlogn)。二分的的l和r,表示当前方案下最远可跳的距离的范围,边界条件需注意,若去除跳跃次数这一约束条件(即可无限次跳),青蛙能跳到对岸,至少需要可跳的最远距离就是相邻石头(还包括石头与岸边)距离中的最大距离,这就确定了l,还有r最多就是L(当n=0)。解法也是看了discuss里大佬的,巧妙之处在于在d数组前面加了起初离岸边0距离,和最后对岸距岸边L距离,这样便于check里判断满足当前假定条件的可跳到的最长距离,还有设置青蛙当前位置标记。最后比较跳跃次数即可。由于数据过大,需要scanf读入,还需注意二分写法。
主要代码
int L,n,m;
bool check(vector<int>& d,int dis){
int ans=0,pos=0;
for(int i=1;i<=n;i++){
if(d[i]-d[pos]<=dis&&d[i+1]-d[pos]>dis){
ans++;
pos=i;
}
}
ans++;
return ans<=m;
}
void solve(){
vector<int> d(n+2);
for(int i=1;i<=n;i++){
scanf("%d",&d[i]);
}
d[n+1]=L;
sort(d.begin(),d.end());
int max1=0;
for(int i=1;i<=n+1;i++)
max1=max(max1,d[i]-d[i-1]);//求l
int l=max1,r=L;
while(l<r){
ll mid=(l+r)>>1;
if(check(d,mid))
r=mid;//左区间
else
l=mid+1;//右区间
}
printf("%d\n",l);
}
int main(){
// ios::sync_with_stdio(false);
// cin.tie(0);
while(~scanf("%d%d%d",&L,&n,&m))
solve();
return 0;
}