《ybtoj高效进阶》第五部分第六章例题3 耗费体力

题目大意

跳跳虎喜欢在树林间跳跃,它从一棵较高的树跳到一棵较矮的树不需要消耗体力,否则消耗一点体力。

给出一排树,在一轮游戏的开始,跳跳虎在第 1 1 1棵树,它要跳到第 n n n棵树。每轮游戏有一个步伐限制 ,跳跳虎只能从第 i i i棵树跳到第 j ( i < j < = i + x ) j(i<j<=i+x) j(i<j<=i+x)棵树 ,求每轮游戏最少耗费多少体力。

思路

显然单调队列优化dp。
f i f_i fi为前i个耗费最小体力值。
f i = m i n ( f j + 是 否 需 要 耗 费 体 力 ) ( m a x ( 0 , i − x ) < = j < i ) f_i=min(f_j+是否需要耗费体力)(max(0,i-x)<=j<i) fi=min(fj+)(max(0,ix)<=j<i)
剩下就是单调队列优化min过程,判断是否需要耗费体力是这样的:
若当前队首的体力耗费严格>现在的耗费,则队首出队。
若当前队首的体力耗费
=现在的耗费但现在的树比队首的
,则队首出队。
现在的位置入队。

在处理某一位时,先把无效值出队,然后取队首的耗费,若队首比现在矮,再++。

实现见代码。
code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<deque>
using namespace std;
int n,a[1000006],f[1000006],m,x;
deque<int> o;
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	scanf("%d",&m);
	while (m--)
	{
		scanf("%d",&x);
		o.clear();
		memset(f,127,sizeof(f));
		f[1]=0;
		o.push_back(1);
		for (int i=2;i<=n;i++)
		{
			while (o.size()&&i-o.front()>x) o.pop_front();
			if (a[o.front()]>a[i]) f[i]=f[o.front()];
			else f[i]=f[o.front()]+1;
			while (o.size()&&(f[o.back()]>f[i]||f[o.back()]==f[i]&&a[o.back()]<=a[i])) o.pop_back();
			o.push_back(i);
		}
		cout<<f[n]<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值