储水

题目传送门

整体思路:二分答案

这个题目一眼二分,然后我就写了一个这个

#include<bits/stdc++.h>
using namespace std;
#define int long long

int n,a[1000001];

bool check(int x){
    for(int i=2;i<=n;i++){
        if(a[i]+x<a[i-1]-x) return 0;
    }
    return 1;
}

signed main(){
    cin.tie(0)->sync_with_stdio(0);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    int l=-1,r=1e10+1;
    while(l+1<r){
        int m=l+r>>1ll;
        if(check(m)) r=m;
        else l=m;
    }
    cout<<r<<endl;
}

大概就是说,我们去判断m作为答案可不可以。不难发现,如果前一个数最小的可能值要比当前这个数的最小可能值要大,那么这个答案是不行的,return 0。否则如果都ok,那就return 1。
提交了,获得二十分的好成绩
为什么会这样?
看一下下面这个图片

图片1.png

这解释了刚刚的为什么不对

所以我们因该贪心一下,记录一个num,就是当前的值,接下来的值不能比它小
所以初始化num=\(a_1-x\)(x表示当前正在检查的答案)
然后,假设当前遍历到了\(i\)这个数。如果\(a_i+x≥num\),说明合法,更新num,\(num=max(num,a_i-x)\)
否则,return 0。
如果所有的都合法,return 1。
结束了……

代码如下

#include<bits/stdc++.h>
using namespace std;
#define int long long

int n,a[1000001];

bool check(int x){
    int num=a[1]-x;
    for(int i=1;i<=n;i++){
        if(a[i]+x>=num) num=max(num,a[i]-x);
        else return 0;
    }
    return 1;
}

signed main(){
    cin.tie(0)->sync_with_stdio(0);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    int l=-1,r=1e10+1;
    while(l+1<r){
        int m=l+r>>1;
        if(check(m)) r=m;
        else l=m;
    }
    cout<<r<<endl;
}
posted @ 2026-01-24 11:45  zhangruotian_Max  阅读(2)  评论(0)    收藏  举报