NMS
题目描述
某巨魔需要找一个叫 Nimas 的 NPC 完成任务,他来到了某个大湖泊,湖泊上有个湖心岛,Nimas 就在上面。
巨魔无法从湖中游到湖心岛,因为水中会拉到很多怪物,会耗费大量时间。
所幸的是,在湖边有
N
个依次连接到湖心岛的木桩,标号
对于这个巨魔来说,每个木桩都有个技巧值。巨魔可以很容易地在技巧值低的木桩上站稳,但是对于技巧值高的木桩,巨魔需要很好的微操才能在木桩上站稳脚跟。
巨魔的跳跃方式有一定规律:即如果巨魔在木桩
现在巨魔在
1
号木桩上,它希望最后它能站在第
输入格式
第一行一个数字
N
,
接下来一行
输出格式
输出一行,即最小技巧值总和,如果不存在方案则输出 -1(不带引号) 。
样例输入
5 1 3
1 2 3 4 5
样例输出
8
样例解释
从
数据范围
30%
的数据:
1≤L≤R≤N≤1000
。
100%
的数据:
1≤L≤R≤N≤106
、
1≤s[i]≤109
Solution
设
f[i]
表示当前在
i
木桩上的总的最小技巧值。
这个方程可以用单调队列进行优化。
Code
#include <iostream>
#include <cstdio>
#include <cstring>
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)<(y)?(x):(y))
#define LL long long
using namespace std;
int n,l,r,tail,front;
LL f[1000010],w[1000010],q[1000010][2],oo;
int main(){
freopen("Nimas.in","r",stdin);
freopen("Nimas.out","w",stdout);
memset(f,0x3f,sizeof f);oo=f[0];
scanf("%d%d%d",&n,&l,&r);
for(int i=1;i<=n;i++)scanf("%lld",&w[i]);
f[1]=w[1];
q[++tail][0]=q[++front][1]=f[1];
q[tail][1]=q[front][1]=1;
for(int i=2;i<=n;i++){
int minx=Max(1,i-r),maxn=i-l;
if(minx>maxn)continue;
while(q[tail][1]<minx&&tail<=front)tail++;
if(i-l>=1){
while(q[front][0]>f[i-l]&&front>tail){
--front;
}
if(q[front][0]<f[i-l]){
q[++front][0]=f[i-l];
q[front][1]=i-l;
}
else{
q[front][0]=f[i-l];
q[front][1]=i-l;
}
}
f[i]=q[tail][0]+w[i];
}
if(f[n]!=oo)printf("%lld\n",f[n]);
else printf("-1\n");
return 0;
}