P3957 跳房子

Posted xiaoyezi-wink

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3957 跳房子相关的知识,希望对你有一定的参考价值。

P3957 跳房子

祭奠一下逝去的时间

技术图片
技术图片

题解

50pt Solution

看到这个题直觉想到是DP 但是不会写

我们可以二分答案,花费金币为 (mid) ,二分枚举 (mid)

我们设置 (f[i]) 为到达第 (i) 个节点时的最大得分,由于跳房子是一直往右跳的,所以 (f[i]) 一定是由它之前的节点中得分最大的转移过来的,所以有:

for(int i=1;i<=n;i++)
      for(int j=i-1;j>=0;j--){
        if(x[i]-x[j]>=lef&&x[i]-x[j]<=rig)
           f[i]=max(f[i],f[j]+s[i]);
        if(f[i]>k) return 1;
      }

但是这题数据太大了。。。(n^2) 只能 (50pt)

(code)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<queue>
using namespace std;

typedef long long ll;

inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'||ch>'9') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

const int maxn=5e5+10,inf=-1e9+10;
int n,d,k;
int s[maxn],x[maxn];
int l=0,r=0,mid=0;
ll f[maxn];
int ans;

bool check(int mid)
{
    for(int i=1;i<=n;i++) f[i]=inf;
    int lef=max(1,d-mid);
    int rig=d+mid;
    for(int i=1;i<=n;i++)
      for(int j=i-1;j>=0;j--){
        if(x[i]-x[j]<lef) continue;
        if(x[i]-x[j]>rig) break;
        f[i]=max(f[i],f[j]+s[i]);
        if(f[i]>k) return 1;
      }
    return 0;
}

int main()
{
    n=read();d=read();k=read();
    for(int i=1;i<=n;i++){
        x[i]=read();s[i]=read();
        if(s[i]>0) ans+=s[i];
        r=max(r,x[i]);
    }
    if(ans<k){
        printf("-1
");
        return 0;
    }
    while(l<r){
        mid=(l+r)>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    printf("%d
",r);
    
    return 0;
}

100pt Solution

满分要二分+DP+单调队列

我们又上面可知

(f[ i ]=max( f[j] )+s[i] ,j<i)

而且随着 (i) 不断往前跳,向前更新,(j) 一定会有不在弹跳范围内的,所以由单调性可知可以使用单调队列

队列队首维护使得 $f[i] $ 最大的那个点下标

我们枚举 (j) ,只需要枚举一遍就行了,(j) 是那个待加入的点的下标,如果它在弹跳范围内,而且下标小于 (i) ,就把它加入到队列中的合适位置,加入之后仍然保持队列单调性,弹出超出合法弹跳区间的点,如果队列非空就更新 $f[i] $ 的值

主体部分:

bool check(ll mid)
{
    q.clear() ;
    for(int i=1;i<=n;i++) f[i]=inf;f[0]=0;
    ll lef=(d-mid<0?1:d-mid);
    ll rig=d+mid;
    int j=0;
    for(int i=1;i<=n;i++){
        while(x[i]-x[j]>rig) j++;
        while(x[i]-x[j]<=rig&&x[i]-x[j]>=lef&&j<i){
            while(!q.empty() &&(f[j]>=f[q.back() ]||x[i]-x[q.back()]>rig)) q.pop_back() ;
            q.push_back(j) ;
            j++;
        }
        while(!q.empty() &&x[i]-x[q.front() ]>rig) q.pop_front() ;
        if(!q.empty()) f[i]=f[q.front()]+s[i];
        if(f[i]>=k) return 1;
    }
    return 0;
}

(code)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<queue>
using namespace std;

typedef long long ll;

inline ll read()
{
    ll ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'||ch>'9') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

const int maxn=5e5+10;
const ll inf=-1e18+10;
int n;
ll k,d;
ll s[maxn],x[maxn];
ll l=0,r=0,mid=0;
ll f[maxn];
deque<ll>q;

bool check(ll mid)
{
    q.clear() ;
    for(int i=1;i<=n;i++) f[i]=inf;f[0]=0;
    ll lef=(d-mid<0?1:d-mid);
    ll rig=d+mid;
    int j=0;
    for(int i=1;i<=n;i++){
        while(x[i]-x[j]>rig) j++;
        while(x[i]-x[j]<=rig&&x[i]-x[j]>=lef&&j<i){
            while(!q.empty() &&(f[j]>=f[q.back() ]||x[i]-x[q.back()]>rig)) q.pop_back() ;
            q.push_back(j) ;
            j++;
        }
        while(!q.empty() &&x[i]-x[q.front() ]>rig) q.pop_front() ;
        if(!q.empty()) f[i]=f[q.front()]+s[i];
        if(f[i]>=k) return 1;
    }
    return 0;
}

int main()
{
    n=read();d=read();k=read();
    for(int i=1;i<=n;i++) x[i]=read(),s[i]=read();
    l=0,r=x[n];
    while(l<r){
        mid=(l+r)>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    if(!check(l)) {
        printf("-1
");
        return 0;
    }
    printf("%lld
",l);
    return 0;
}

以上是关于P3957 跳房子的主要内容,如果未能解决你的问题,请参考以下文章

P3957 跳房子[二分答案][dp][单调队列]

单调队列P3957 跳房子

[luogu5004]专心OI - 跳房子

租房子(用户登录) 最主要的 查!!!!!!(只显示查的页面代码)

17年,除了代码收入还有房子收入

蓝桥杯--造房子