2018.09.23 孙悟空大战鲤鱼精(单调队列优化dp)

描述

孙悟空大战鲤鱼精,孙悟空在通天河遇到鲤鱼精,他嫉恶如仇,看见妖精就手痒(忘了自己是妖精)。但是鲤鱼精知道孙悟空的厉害,在孙悟空来到通天河,鲤鱼精就跑到了河对面。于是孙悟空就去追鲤鱼精。 我们可以把通天河看成一列格子,从0编号到N,孙悟空只能从小号格子到大号格子,当他在第i号格子,他移动的时候只会到[i+L,i+R]的某一格。每一个格子有一个魔法数Wi,第0号格子指数诶0,当孙悟空在某一格停留时就会获得这个魔法值Wi。孙悟空希望通过通天河时获得最大的魔法,这样他才能狠打一下鲤鱼精,可是孙悟空战斗力高,脑袋不咋地(猴脑),他希望你来帮他计算如何达到对岸,他开始在第0号 格。他只要最后一步落在的位置编号大于了N就算通过了通天河

输入

第1行:3个正整数N, L, R
第2行:N+1个整数,第i个数表示编号为i-1的格子的魔法数A[i-1]

输出

第1行:一个整数,表示最大魔法值。保证不超过2^31-1 第2行:空格分开的若干个整数,表示孙悟空前进的路线,最后输出-1表示到达对岸

样例输入

5 2 3
0 12 3 11 7 -2

样例输出

11
0 3 -1

提示

对于60%的数据:N <= 10,000
对于100%的数据:N <= 200,000
对于所有数据 -1,000 <= A[i] <= 1,000且1 <= L <= R <= N


一道带了spj的单调队列优化dp。
注意元素入队和出队的条件。
代码:

#include<bits/stdc++.h>
#define N 200005
using namespace std;
inline int read(){
	int ans=0,w=1;
	char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans*w;
}
inline int write(int x){
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar((x%10)^48); 
}
int n,l,r,pred[N],a[N],f[N],q[N],print[N],hd,tl,tot=0;
int main(){
	n=read(),l=read(),r=read(),hd=1,tl=0;
	for(int i=0;i<=n;++i)a[i]=read();
	for(int i=1;i<=n;++i)f[i]=-1e9;
	for(int i=1;i<=n;++i){
		while(hd<=tl&&q[hd]<i-r)++hd;
		if(i>=l){
			while(hd<=tl&&f[q[tl]]<f[i-l])--tl;
			q[++tl]=i-l;
		}
		if(hd<=tl)f[i]=f[q[hd]],pred[i]=q[hd];
		f[i]+=a[i];
	}
	int ans=n-r+1;
	for(int i=n-r+2;i<=n;++i)if(f[i]>f[ans])ans=i;
	write(f[ans]),puts("");
	for(int i=ans;i;i=pred[i])print[++tot]=i;
	print[0]=-1,print[++tot]=0;
	for(int i=tot;~i;--i)write(print[i]),putchar(' ');
	return 0;
}

转载于:https://www.cnblogs.com/ldxcaicai/p/9738225.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值