题面
小青蛙住在一条河边,它想到河对岸的学校去学习。小青蛙打算经过河里的石头跳到对岸。
河里的石头排成了一条直线,小青蛙每次跳跃必须落在一块石头或者岸上。不过,每块石头有一个高度,每次小青蛙从一块石头起跳,这块石头的高度就会下降 1,当石头的高度下降到 0 时小青蛙不能再跳到这块石头上(某次跳跃后使石头高度下降到 0 是允许的)。
小青蛙一共需要去学校上
x 天课,所以它需要往返 2x 次。当小青蛙具有一个跳跃能力 y 时,它能跳不超过 y 的距离。
请问小青蛙的跳跃能力至少是多少才能用这些石头上完x 次课。
前置题目
可以先去看一看这道题
看完这道题之后,不难发现(显而易见的),两道题几乎一模一样 (就是不知道为什么青蛙过河明明是进阶版的确是绿题) ,青蛙过河只不过是在这道题的基础上加了一个二分
分析
前置题目的思路我也讲一下
算了还是引用大佬的题解罢
先说结论:
最多通过的青蛙的数量就是每个长度为 l 的区间中石头数量的最小值。
我们考虑一段长度为 l 的区间,
因为青蛙最多跳 l 的距离,
不难想到,每只青蛙都一定会在这个区间落下至少一次。
因为一定可以从另一个石子数大于等于 n 的区间跳过来,
所以这样取出的答案是可行的。
那么我们就得到了结论:
最多通过的青蛙的数量就是每个长度为 l 的区间中石头数量的最小值。
青蛙过河分析
有了前置题目,我们就可以把题目转化为求一个最小的数y使得有2x只青蛙能跳过河(差不多就是前置题目倒过来)
那这样就可以轻易的想到用二分的方法
关于可二分性
其实这个不难说明,假设 y1 < y2,倘若青蛙在y1时能跳过河,那么青蛙在y2的时候就一定可以跳过去(可以理解成y2包含y1)
二分范围
很显然我写这个是为了水字数
青蛙想跳过河,那么青蛙的最小跳跃范围至少要是1,最大的自然就是一步跳到和对岸也就是n
代码实现
check函数
既然已经有了前置题目,那我们只需要把前置题目的代码复制过来缝合一下就好了
bool check(int l){
int cnt = INF;//赋为一个很大的数 跟大佬的rp一样高
for(int i = l+1; i <= n; i++){
cnt= min(cnt,b[i]-b[i-l]);
}
return cnt >= 2*x;
}
然后你满心欢喜的去提交代码
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1e7+5;
int n, x;
int a[N],b[N];
int ans = INF;
bool check(int l){
int cnt = INF;
for(int i = l+1; i <= n; i++){
cnt= min(cnt,b[i]-b[i-l]);
}
return cnt >= 2*x;
}
int main(){
cin >> n >> x;
for(int i = 2; i <= n; i++){
cin >> a[i];
b[i] = b[i-1] + a[i];
}
int l = 1, r = n;
while(l < r){
int mid = (l + r) >> 1;
if(check(mid)){
r = mid;
ans = mid;
}else{
l = mid+1;
}
}
cout << ans << endl;
return 0;
}
但是却WA了一个点
打油诗一首
我是一只小青蛙,我在洛谷养青蛙。
我让青蛙去上学,青蛙回我WA WA WA。
因为我们在二分的时候没有判断一步跳到的情况的
但是很显然一步到位的情况是绝对存在的
所以我们只需要把ans赋值为n
丑陋的AC代码
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1e7+5;
int n, x;
int a[N],b[N];
int ans = INF;
bool check(int l){
int cnt = INF;
for(int i = l+1; i <= n; i++){
cnt= min(cnt,b[i]-b[i-l]);
}
return cnt >= 2*x;
}
int main(){
cin >> n >> x;
ans = n;
for(int i = 2; i <= n; i++){
cin >> a[i];
b[i] = b[i-1] + a[i];
}
int l = 1, r = n;
while(l < r){
int mid = (l + r) >> 1;
if(check(mid)){
r = mid;
ans = mid;
}else{
l = mid+1;
}
}
cout << ans << endl;
return 0;
}