码迷,mamicode.com
首页 > 其他好文 > 详细

P3957 跳房子

时间:2020-01-05 19:00:42      阅读:59      评论:0      收藏:0      [点我收藏+]

标签:lib   etc   queue   数据   def   --   com   ios   ast   

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\n");
        return 0;
    }
    while(l<r){
        mid=(l+r)>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    printf("%d\n",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\n");
        return 0;
    }
    printf("%lld\n",l);
    return 0;
}

P3957 跳房子

标签:lib   etc   queue   数据   def   --   com   ios   ast   

原文地址:https://www.cnblogs.com/xiaoyezi-wink/p/12152901.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!