跳棋

1 篇文章 0 订阅

题目描述

小明迷恋上了一个新的跳棋游戏,游戏规则如下:棋盘是一排从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
状态转移方程:F[i]=A[i]+min(F[j]) (j=i-r-1~i-l-1)
直接暴力N*N搜肯定是不行的

So,可以用小根堆来维护一个最小值,就OK啦!
(其实是因为OJ跑得快,这样的数据带一个log N是过不了的,数据正解应该是用单调队列来维护)

代码:

var
        f,a,q,d,o,p,g:array[0..1000000]of int64;
        n,l,r,i,j,k,s,t,len,ls,x,y,z:longint;
procedure down(x:longint);
var
        i,j,t:longint;
begin
        i:=x;
        while (i*2<=len)and(f[d[i*2]]<f[d[i]])or(i*2+1<=len)and(f[d[i*2+1]]<f[d[i]]) do
        begin
                j:=i*2;
                if (f[d[j+1]]<f[d[j]])and(j+1<=len) then inc(j);
                q[d[i]]:=j;
                q[d[j]]:=i;
                t:=d[i];
                d[i]:=d[j];
                d[j]:=t;
                i:=j;
        end;
end;
procedure up(x:longint);
var
        i,j:longint;
begin
        i:=x;
        while (f[d[i div 2]]>f[d[i]])and(i>1) do
        begin
                q[d[i div 2]]:=i;
                q[d[i]]:=i div 2;
                x:=d[i div 2];
                d[i div 2]:=d[i];
                d[i]:=x;
                i:=i div 2;
        end;
end;
procedure charu(t:longint);
begin
        d[len+1]:=t;
        q[t]:=len+1;
        inc(len);
        up(len);
end;
procedure shanchu(x:longint);
var
        i:longint;
begin
        dec(len);
        i:=q[x];
        q[x]:=0;
        q[d[len+1]]:=i;
        d[i]:=d[len+1];
        up(i);
        down(i);
end;
begin
        assign(input,'jump.in');
        reset(input);
        assign(output,'jump.out');
        rewrite(output);
        readln(n,l,r);
        for i:=1 to n do
        begin
                read(a[i]);
                f[i]:=maxlongint;
        end;
        for i:=l+1 to n do
        begin
                charu(i-l-1);
                if i>r+1 then shanchu(i-r-2);
                if len>0 then f[i]:=f[d[1]]+a[i];
        end;
        if f[n]<maxlongint then writeln(f[n])
        else writeln(-1);
end.
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值