跳房子

传送门

其实这道题只要想清楚
dp循环变量的意义
以及dp所求的值
就非常简单了

解法:

\(i\)点获得的分为\(S_i\)

先来考虑一个方面的问题

若我们知道\(g\) 即机器人性能的改变值

怎么求获得的最多的分

可以想到\(dp\)

\(dp[i]\)表示到i点为止可以获得的最大分

状态转移方程即为 \(dp[i]=max_{j=0->i-1}\{dp[j]\}+S_i\ \text{条件:}(d-g\le X_i-X_j\le d+g)\)

(从0开始是因为可以从一开始位置就直接跳到\(i\)点)

p.s.可以发现其实并不需要枚举j,用单调队列维护即可。

这样我们就找到了知道\(g\)的情况下求获得最大分的方法

接下来就用2分找\(g\)就可以了

当然题目未给上界(有是有,但是为\(10^9\)

所以我们应先用倍增来求\(g\)的区间

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define inf 2000000000
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dwn(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
typedef long long ll;
int l,r;
int n,d,k,x[500010],s[500010];
ll dp[500010],sum=0;
int solve(int g)
{
    memset(dp,-127,sizeof(dp));
    int lp=max(1,d-g),rp=d+g;
    ll ans=-inf;
    dp[0]=0;
    rep(i,1,n)
    {
        dwn(j,i-1,0)
        {
            if(x[i]-x[j]>rp) break;
            if(x[i]-x[j]<lp) continue;
            dp[i]=max(dp[i],dp[j]+s[i]);
        }
        ans=max(ans,dp[i]);
        if(ans>=k) return ans;
    }
    return ans;
}
int main()
{
    scanf("%d%d%d",&n,&d,&k);
    rep(i,1,n)
    {
        scanf("%d%d",&x[i],&s[i]);
        if(s[i]>0)sum+=s[i];
    }
    if(sum<k)
    {
        printf("-1\n");
        return 0;
    }
    r=10;
    while(true)
    {
        if(solve(r)>=k) break;
        r*=10;
    }
    l=r/10;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(solve(mid)>=k)
            r=mid;
        else
            l=mid+1;
    }
    printf("%d\n",l);
    return 0;
}

单调队列优化:

int q[500010],ql,qr;
int solve(int g)
{
    memset(dp,-127,sizeof(dp));
    int lp=max(1,d-g),rp=d+g,cnt=0;
    dp[0]=0;
    ql=1,qr=0;
    rep(i,1,n)
    {
        while(true)
        {
            while(ql<=qr&&cnt<i&&x[i]-x[cnt]>=lp&&dp[cnt]>=dp[q[qr]]) qr--;
            if(cnt<i&&x[i]-x[cnt]>=lp) q[++qr]=cnt++;
            else break;
        }
        while(ql<=qr&&x[i]-x[q[ql]]>rp) ql++;
        if(ql<=qr) dp[i]=dp[q[ql]]+s[i];
        if(dp[i]>=k) return dp[i];
    }
    return -inf;
}

但是由于这道题枚举时边界的特殊性

用单调队列优化并不能快多少

所以当做练练手写写吧

posted @ 2019-05-27 22:26  zmy蒟蒻  阅读(148)  评论(0编辑  收藏  举报