跳房子

洛咕

题意:在地面上确定一个起点,然后在起点右侧画\(n(n<=500000)\)个格子,这些格子都在同一条直线上.每个格子内有一个数字(整数),表示到达这个 格子能得到的分数.玩家第一次从起点开始向右跳,跳到起点右侧的一个格子内.第二次再从当前位置继续向右跳,依此类推.规则规定:玩家每次都必须跳到当前位置右侧的一个格子内.玩家可以在任意时刻结束游戏,获得的分数为曾经到达过的格子中的数字之和.每一次可以跳的固定距离为\(d\),然后花费\(g\)元,可以跳的区间范围为\(max(d-g,1),d+g\),求最少花费多少钱可以获得至少\(k\)分?

答案显然具有单调性,所以可以二分最小花费为\(mid\),得到可以跳的区间范围为\([max(d-mid,1),d+mid]\).

\(f[i]\)表示跳到第\(i\)个格子能够获得的最大分数,\(f[i]=f[j]+val[i]\),其中\((max(d-mid,1)<=dis(i-j)<=d+mid)\),\(val[i]\)表示第i格的得分.

这个\(j\)可以\(n^2\)枚举(50分),也可以单调队列维护.但是本题的单调队列需要用到双端队列\(deque\),因为\(j\)既有上界又有下界.

时间复杂度\(O(nlog_{x_n}).\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=500005;
int n,d,k,x[N],val[N];ll sum,f[N];
inline bool check(int mid){
	for(int i=0;i<=n;++i)f[i]=-1e18;f[0]=0;
//这里一定要赋值为负无穷,因为格子的分数可能是负的
//没有的话,只有50分
	int minn=max(d-mid,1),maxn=d+mid;//跳的上下界
	int j=0;deque<int>q;//在里面建立队列就不用初始化了
	for(int i=1;i<=n;++i){
		while(j<i&&x[i]-x[j]>=minn){
			while(q.size()&&f[j]>=f[q.back()])q.pop_back();
			q.push_back(j);++j;
		}//把符合条件的j加进队列里面,并维护单调性
		while(q.size()&&x[i]-x[q.front()]>maxn)q.pop_front();//队列前面也要维护
		if(q.size())f[i]=f[q.front()]+val[i];//更新
		if(f[i]>=k)return 1;//判断
	}
	return 0;
    
	/*
    暴力的n方做法
    for(int i=0;i<=n;++i)f[i]=0;
	int minn=max(d-mid,1),maxn=d+mid;
	for(int i=1;i<=n;++i){
		for(int j=0;j<i;++j){
			if(x[i]-x[j]>=minn&&x[i]-x[j]<=maxn)
				f[i]=max(f[i],f[j]+val[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();val[i]=read();
		if(val[i]>0)sum+=val[i];
	}
	if(sum<k){puts("-1");return 0;}//特判
	int l=0,r=x[n],ans,mid;//最大花费就是最远的那个格子的距离
	while(l<=r){
		mid=(l+r)>>1;
		if(check(mid)){
			ans=mid;
			r=mid-1;
		}
		else l=mid+1;
	}
	printf("%d\n",ans);
    return 0;
}

posted on 2019-09-27 19:47  PPXppx  阅读(206)  评论(0编辑  收藏  举报