(紀中)2170. 跳棋【單調隊列】

(File IO): input:jump.in output:jump.out
時間限制: 1000 ms 空間限制: 131072 KB 具體限制


題目描述
小明迷戀上了一個新的跳棋遊戲,遊戲規則如下:棋盤是一排從00開始,順序編號的格子,遊戲開始時你位於00號格子,你每次只能往編號大的格子跳,而且你每次至少需要跳過LL個格子,至多隻能跳過RR個格子。每個格子都有一個給定的傷害值,顯然你希望得到的傷害值越少越好。
你能告訴小明他當他跳到最後一個格子時受到的累積傷害值最小爲多少嗎?
如果無論如何小明都無法跳到最後一個格子,這個時候你需要輸出1”-1”
注:從i號格子跳過xx個格子表示從i號格子跳到第i+x+1i+x+1號格子。


輸入
輸入文件jump.injump.in第一行有三個整數nLn、LRnR,n表示格子的編號從00nnLLRR表示最少需要跳過的格子數和最多能夠跳過的格子數。
第二行有nn個正整數,兩個數字間用空格隔開,表示每個格子的傷害值。

輸出
輸出文件jump.outjump.out僅有一個整數,表示受到的最小傷害值,保證結果小於maxlongintmaxlongint


樣例輸入
10 2 6
1 3 5 7 9 2 4 6 8 10

樣例輸出
12


數據範圍限制
5050%的數據,1<=n<=10001 <= n <= 1000
6565%的數據,1<=n<=100001 <= n <= 10000
100100%的數據,1<=n<=10000001<=L<=R<=n1 <= n <= 1000000,1 <= L <= R <= n
其中有1515%的數據,1<=n<=10000001<=L<=R<=101 <= n <= 1000000,1 <= L <= R <= 10


提示
在這裏插入圖片描述


解題思路
這道題顯而易見的是動態規劃。轉移方程也非常好推,我們把 f[i]f[i] 作爲到第I格的最小傷害值,轉移方程就是
f[i]=minf[j](j=ir1 il1)+a[i]f[i]=min{f[j](j=i-r-1~i-l-1)}+a[i];
顯而易見,動態規劃的時間複雜度是OnnO(n*n)的,肯定TLE,但是有沒有一種算法可以快速枚舉區間最值呢?
有四種方法:1(1)優先隊列2(2)線段樹 (3)堆4(4)單調隊列
而我們這次講解最簡易的單調隊列解法,
單調隊列最本質的本質就是用來求定區間最值的,用它也非常方便。


代碼

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章