Noip2017普及组T4 跳房子 二分答案 单调队列

题目描述

跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一。

跳房子的游戏规则如下:

在地面上确定一个起点,然后在起点右侧画 n 个格子,这些格子都在同一条直线上。每个格子内有一个数字( 整数),表示到达这个格子能得到的分数。玩家第一次从起点开始向右跳, 跳到起点右侧的一个格子内。第二次再从当前位置继续向右跳,依此类推。规则规定:

玩家每次都必须跳到当前位置右侧的一个格子内。玩家可以在任意时刻结束游戏,获得的分数为曾经到达过的格子中的数字之和。

现在小 R 研发了一款弹跳机器人来参加这个游戏。但是这个机器人有一个非常严重的缺陷,它每次向右弹跳的距离只能为固定的 d。小 R 希望改进他的机器人,如果他花 g 个金币改进他的机器人,那么他的机器人灵活性就能增加 g, 但是需要注意的是,每次弹跳的距离至少为 1。 具体而言, 当g < d时, 他的机器人每次可以选择向右弹跳的距离为 d-g, d-g+1,d-g+2, …, d+g-2, d+g-1, d+g; 否则( 当g ≥ d时),他的机器人每次可以选择向右弹跳的距离为 1, 2, 3, …, d+g-2, d+g-1, d+g。

现在小 R 希望获得至少 k 分,请问他至少要花多少金币来改造他的机器人。


这道题看到之后马上二分答案然后dp来check是否成立,但是如果直接dp的话就会有[max(1,d-g),g+d]*n*logn的复杂度最后五个点就会T。由于在dp过程中的每个区间都是固定的,就可以用区间滑块或者就是用单调队列进行优化。


附上ac代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=500005;

int len[maxn],value[maxn],dp[maxn],que[maxn*2];

int n,d,k,maxlow;

int mymax(int a,int b)
{
	return a>b?a:b;
}

int maxcost(int a)
{
	memset(dp,-127,sizeof(dp));
    int head=1,tail=0;
	int mi=mymax(d-a,1);
	int mx=d+a;
	int rt=0,fir=-1;
    que[++tail]=0,dp[0]=0;
    for (int i=1;i<=n;i++)
    {
        if (len[i]<mi) continue;
        if (len[i]>=mi&&fir==-1)
            fir=i;
        if (len[i]-len[i-1]>mx) break;
        while (len[i]-len[fir]>=mi&&fir<i) 
        {
            while (head<=tail&&dp[fir]>dp[que[tail]]) tail--; 
            if(dp[fir]!=-0x7f7f7f7f) que[++tail]=fir; 
            fir++;
        }
        while (head<=tail&&len[que[head]]+mx<len[i]) head++; 
        if (head>tail) 
            dp[i]=-0x7f7f7f7f;
        else
            dp[i]=dp[que[head]]+value[i];
        if (dp[i]>rt) 
            rt=dp[i];
    }
    return rt ; 
}

int main()
{
	freopen("jump.in","r",stdin);
	freopen("jump.out","w",stdout);
	scanf("%d%d%d",&n,&d,&k);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&len[i]);
		scanf("%d",&value[i]);
	}
	int lf=0;
	int rg=len[n];
	while (lf!=rg)
	{
		int mid=(lf+rg)>>1;
		if (maxcost(mid)>=k)
		   rg=mid;
		else
		   lf=mid+1;
	}
	if (maxcost(lf)<k)
	   printf("-1\n");
	else
	   printf("%d\n",lf);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/beloved_rancy/article/details/79679790