题目描述
小明迷恋上了一个新的跳棋游戏,游戏规则如下:棋盘是一排从0开始,顺序编号的格子,游戏开始时你位于0号格子,你每次只能往编号大的格子跳,而且你每次至少需要跳过L个格子,至多只能跳过R个格子。每个格子都有一个给定的伤害值,显然你希望得到的伤害值越少越好。
你能告诉小明他当他跳到最后一个格子时受到的累积伤害值最小为多少吗?
如果无论如何小明都无法跳到最后一个格子,这个时候你需要输出”-1”。
注:从i号格子跳过x个格子表示从i号格子跳到第i+x+1号格子。
输入
输入文件jump.in第一行有三个整数n、L和R,n表示格子的编号从0到n。L和R表示最少需要跳过的格子数和最多能够跳过的格子数。
第二行有n个正整数,两个数字间用空格隔开,表示每个格子的伤害值。
输出
输出文件jump.out仅有一个整数,表示受到的最小伤害值,保证结果小于maxlongint。
样例输入
10 2 6
1 3 5 7 9 2 4 6 8 10
样例输出
12
数据范围限制
50%的数据,1 <= n <= 1000
65%的数据,1 <= n <= 10000
100%的数据,1 <= n <= 1000000,1 <= L <= R <= n
其中有15%的数据,1 <= n <= 1000000,1 <= L <= R <= 10
提示
分析
这题其实裸的DP转移方程很好推。但是只能拿到80pts。所以可以选择几种优化方式,我用了比较简单的单调队列优化。注意边界的判断和转移。
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long n,l,r,a[1000001],f[1000001],que[1000001];
int main()
{
freopen("jump.in","r",stdin);
freopen("jump.out","w",stdout);
cin>>n>>l>>r;
for(int i=1;i<=n;i++)
{
cin>>a[i];
f[i]=0x3fffff;//初始最大
}
int h=1,t=0;
f[0]=0;
for(int i=1;i<=n;i++)
{
/*单调队列优化*/
if(i-l-1>=0)//至少大于边界
{
while(h<=t&&f[que[t]]>=f[i-l-1])
{
t--;//消除不可能
}
t++;
que[t]=i-l-1;
}
while(h<=t&&que[h]<i-r-1)
{
h++;
}
if(h<=t) f[i]=a[i]+f[que[h]];//dp转移
}
if(f[n]<0x3fffff) cout<<f[n];
else cout<<-1;
fclose(stdin);
fclose(stdout);
return 0;
}