(File IO): input:jump.in output:jump.out
時間限制: 1000 ms 空間限制: 131072 KB 具體限制
題目描述
小明迷戀上了一個新的跳棋遊戲,遊戲規則如下:棋盤是一排從開始,順序編號的格子,遊戲開始時你位於號格子,你每次只能往編號大的格子跳,而且你每次至少需要跳過個格子,至多隻能跳過個格子。每個格子都有一個給定的傷害值,顯然你希望得到的傷害值越少越好。
你能告訴小明他當他跳到最後一個格子時受到的累積傷害值最小爲多少嗎?
如果無論如何小明都無法跳到最後一個格子,這個時候你需要輸出。
注:從i號格子跳過個格子表示從i號格子跳到第號格子。
輸入
輸入文件第一行有三個整數和表示格子的編號從到。和表示最少需要跳過的格子數和最多能夠跳過的格子數。
第二行有個正整數,兩個數字間用空格隔開,表示每個格子的傷害值。
輸出
輸出文件僅有一個整數,表示受到的最小傷害值,保證結果小於。
樣例輸入
10 2 6
1 3 5 7 9 2 4 6 8 10
樣例輸出
12
數據範圍限制
%的數據,
%的數據,
%的數據,
其中有%的數據,
提示
解題思路
這道題顯而易見的是動態規劃。轉移方程也非常好推,我們把 作爲到第I格的最小傷害值,轉移方程就是
顯而易見,動態規劃的時間複雜度是的,肯定TLE,但是有沒有一種算法可以快速枚舉區間最值呢?
有四種方法:優先隊列線段樹 (3)堆單調隊列
而我們這次講解最簡易的單調隊列解法,
單調隊列最本質的本質就是用來求定區間最值的,用它也非常方便。
代碼
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cmath>
using namespace std;
int n,l,r,h,t;
long long f[1000010],q[1000010],a[1000010];
int main()
{
freopen("jump.in","r",stdin);
freopen("jump.out","w",stdout);
scanf("%d%d%d",&n,&l,&r);
for(int i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
f[i]=2147483647;
}
h=1;
for(int i=1; i<=n; i++)
{
if(i-l-1>=0)
{
while(h<=t&&f[q[t]]>=f[i-l-1])
t--;
t++;
q[t]=i-l-1;
}
while(h<=t&&q[h]<i-r-1)
h++;
if(h<=t)
f[i]=a[i]+f[q[h]];
}
if(f[n]<2147483647)
printf("%lld",f[n]);
else
cout<<-1;
}