P3957[NOIP2017普及组]跳房子

https://www.luogu.com.cn/problem/P3957

https://class.51nod.com/Html/Textbook/ChapterIndex.html#textbookId=126&chapterId=337image-20240723211800507

显然,但是维护滑动窗口有技巧,不能每次插入一个值,因为维护 \(x\) 不方便。

所以考虑一个 \(cur\),每次对于新的 \(i\) 不能跳过时移动 \(cur\),然后队首无法到达出队,最后再取值。

请注意,初始化成 \(-INF\),保证不会从不合法的位置跳过来,否则50pts。

#include<iostream>
#include<cstring>
typedef long long ll;
using namespace std;
const int N=500010;
int n,d,k,x[N],s[N],q[N];
ll f[N];
void read(int &x){
    x=0;
    bool f=0;
    char c=getchar();
    while(!isdigit(c)){
        if(c=='-')f=1;
        c=getchar();}
    while(isdigit(c))x=x*10+c-'0',c=getchar();
    if(f)x=-x;
}
bool check(int g){
    ll ans=0;
    memset(f+1,-0x3f,n*8);
    int hh=0,tt=-1,l=max(d-g,1),r=d+g,cur=0;
    for(int i=1;i<=n;++i){
        while(cur<i&&x[cur]+l<=x[i]){
            while(hh<=tt&&f[q[tt]]<=f[cur])--tt;
            q[++tt]=cur;
            ++cur;
        }
        while(hh<=tt&&x[q[hh]]+r<x[i])++hh;
        if(hh<=tt)f[i]=f[q[hh]]+s[i];
        // printf("f[%d]=%d\n",i,f[i]);
        ans=max(ans,f[i]);
    }
    return ans>=k;
}
int main(){
    #ifdef LOCAL
    freopen("1.txt","r",stdin);
    #endif
    #ifndef LOCAL
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    #endif
    read(n);
    read(d);
    read(k);
    ll tot=0;
    for(int i=1;i<=n;++i)read(x[i]),read(s[i]),tot+=s[i]>0?s[i]:0;
    if(tot<k)return cout<<"-1\n",0;
    int l=0,r=1e9;
    while(l<r){
        int mid=l+r>>1;
        if(check(mid))r=mid;
        else l=mid+1;
    }
    cout<<r;
    // cout<<check(2);
    return 0;
}
posted @ 2024-07-23 21:19  wscqwq  阅读(7)  评论(0编辑  收藏  举报