【P3957】跳房子(单调队列+DP+二分)

终于把这个题缸出来了,话说这题也不是想的那么难。。。

因为最小的最大,所以二分,因为由前面推出后面,所以DP,因为输入单调,朴素DP会T,所以单调队列。要注意的是,这个题数据很大,要开LL,然后DP数组每次要清为一个大负值,因为输入中有负值。然后单调队列的使用还是有些清奇的地方,待会看代码吧。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define re register
#define ll long long
#define mo 2015
using namespace std;
long long n,dis,k;
long long ans,m,cnt,tot,d[5000001],maxd,cost,l,r,flag,leftt,rightt;
long long s[5000001],f[1000001];
ll q[2000001],head,tail;
long long maxx;
inline bool check(int x)
{
    for(re int i=1;i<=n;i++) f[i]=-1e12;
    memset(q,0,sizeof(q));
    head=1;tail=0;
    leftt=max(dis-x,(ll)1);
    rightt=dis+x;
    int p=0;
    for(re int i=1;i<=n;i++)
    {
        while(d[i]-d[p]>=leftt&&p<i)
        {
            while(head<=tail&&f[p]>=f[q[tail]])
            tail--;
            q[++tail]=p;
            p++;
        }
        while(head<=tail&&d[i]-d[q[head]]>dis+x)
        head++;
        if(head>tail)
        continue;
        f[i]=s[i]+f[q[head]];
        if(f[i]>=k)
        return 1;
    }
    return 0;
}
int main()
{
    cin>>n>>dis>>k;
    for(re int i=1;i<=n;i++)
    {
        cin>>d[i]>>s[i];
    }
    int l=0,r=100000001;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(check(mid))
        {
            r=mid-1;
        }else
        l=mid+1;
    }
    cout<<l;
    return 0;
}

 

posted @ 2018-02-07 15:42  ~victorique~  阅读(168)  评论(0编辑  收藏  举报
Live2D