跳房子

链接:

https://www.luogu.org/problemnew/show/P3957

动态规划,单调队列+二分。

//my.cpp.
#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;
/*
定义dp[i]是跳到了第i个位置之后的最大得分。
那么状态转移方程是;
dp[i]=max(dp[j])+a[i]; //其中j是可以跳到i的位置。
如此选择的原因是你思考的那种情况是不可能的。一定要符合事实。
*/
long long MIN= 0x8080808080808080;
const int inf=5e5+7;
typedef long long ll;
struct node
{
    ll dis;
    ll score;
}arr[inf];
ll que[inf],dp[inf];       //单调队列。
int n,d,k;          //不要在意细节,从主要的看起吧。定义一个变量??? 可以吗? 1

long long fun(ll thel,ll ther)          //一种是固定的,还有一种就是像这种不是固定的吧。
{
	memset(que,0,sizeof(que));
	memset(dp,0x80,sizeof(dp));
	dp[0]=0;

    int head=1,tail=0;      //
    int point=0;            //
    for(int i=1;i<=n;i++)   //  关键是在dp[j],用一个变量来保存
    {
        while(arr[point].dis+thel<=arr[i].dis&&point<i)
        {
            if( dp[point]!=MIN )		//定义的是可以跳到其上。
            {
                while(head<=tail&&dp[point]>=dp[que[tail]] )tail--;      //理解还是关键啊。
                que[++tail]=point;      //如此看来,第一部分是新增加的元素进行挤原先队列中的元素。
            }
            point++;
        }
        //之后就是去除不在j的范围中的了。对啊,这俩是相连的。
        while( head<=tail&&arr[ que[head] ].dis+ther<arr[i].dis)head++;
		if(head<=tail)	  //对于这种不是一眼就能看出来的,其中的量是随机的题目,不论何时都要进行判断head是否小于等于tail。
			dp[i]=dp[que[head]]+arr[i].score;
    }
    //之后是从哪一个范围选出最大值呢? 应该是最大的吧。
    long long ans=MIN;
    for(int i=1;i<=n;i++)
        if(dp[i]>ans)
			ans=dp[i];
    return ans;
}

int main()
{
    scanf("%d %d %d",&n,&d,&k);
    long long ans=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld %lld",&arr[i].dis,&arr[i].score);
        if(arr[i].score>0)
            ans+=arr[i].score;
    }
    ll theans=0;
    if(ans<k)
        cout<<-1<<endl;
    else            //定要尝试最为精简才行。
    {
        ll l=0,r=max(arr[n].dis,(ll)d);
        while(l<=r)     //
        {
            ll mid=(l+r)/2;
            ll thel=max( (int)1, int(d-mid));      //理解为是最小的距离吧。
            ll ther=d+mid;
            long long ansans=fun(thel,ther);
			if(ansans>=k)
            {
                theans=mid;
                r=mid-1;
            }
            else
            {
                l=mid+1;
            }
        }
        cout<<theans<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_40799464/article/details/83870034