跳棋

【PrayerOJ-4951】

【题目描述】

小明迷恋上了一个新的跳棋游戏,游戏规则如下:棋盘是一排从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

【样例说明】

 

0

1

3

5

7

9

2

4

6

8

10

【数据规模】

50%的数据,1 <= n <= 1000

65%的数据,1 <= n <= 10000

100%的数据,1 <= n <= 1000000,1 <= L <= R <= n

其中有15%的数据,1 <= n <= 1000000,1 <= L <= R <= 10

【代码】

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

#define RI        register int
#define re(i,a,b) for(RI i=a; i<=b; i++)
#define ms(i,a)   memset(a,i,sizeof(a))

using namespace std;

typedef long long ll;

int const N=1000005;
ll const oo=1e12;

int n,m,r,l;
int a[N],vis[N];
ll f[N];

void up(int x) {
    while(x>1) {
        if(f[a[x/2]]>f[a[x]]) 
            swap(a[x/2],a[x]),x=x/2;
            else break;
    }
}

void down(int x) {
    while(2*x<=m) {
        int k=2*x;
        if(k+1<=m && f[a[k+1]]<f[a[k]]) k++;
        if(f[a[k]]<f[a[x]]) 
            swap(a[k],a[x]),x=k;
            else break; 
    }
}

int main() {
    scanf("%d%d%d",&n,&l,&r);
    re(i,1,n) {
        int v;
        scanf("%d",&v);
        if(i-r-2>=0) vis[i-r-2]=1;
        if(i-l-1>=0) {
            a[++m]=i-l-1;
            up(m);
        }
        while(m && vis[a[1]]) {
            a[1]=a[m--];
            down(1);
        }
        if(m) f[i]=f[a[1]]+v;
            else f[i]=oo;
    }
    if(f[n]>=oo) f[n]=-1;
    cout << f[n] << endl;
    return 0;
}