1. 程式人生 > >跳房子

跳房子

連結:

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;
}