單調隊列優化dp


洛谷p3800(單調隊列優化DP

題目背景

據說在紅霧異變時,博麗靈夢單身前往紅魔館,用十分強硬的手段將事件解決了。

然而當時靈夢在Power達到MAX之前,不具有上線收點的能力,所以她想要知道她能收集多少P點,然而這個問題她答不上來,於是她找到了學OI的你。

題目描述

可以把游戲界面理解成一個NM列的棋盤,有K個格子上有P點,其價值為val(i,j)

初始靈夢可以選擇在第一行的任意一個格子出發,每秒她必須下移一格。

靈夢具有一個左右移動的速度T,可以使她每秒向左或右移動至多T,也可以不移動,並且不能折返。移動可視為瞬間完成,不經過路途上的點,只能獲得目標格子的P點。

求最終她能獲得的POWER值最大是多少?

輸入輸出格式

輸入格式:

第一行四個數字,N,M,K,T

接下來K行每行3個數字x,y,v,代表第x行第y列有一個valvP點,數據保證一個格子上最多只有1P點。

輸出格式:

一個數字

輸入輸出樣例

輸入樣例#1 復制

3 3 4 1

1 1 3

1 2 1

2 2 3

3 3 3

輸出樣例#1 復制

9

說明

對於40%的測試點,1<=N,M,T,K<=200

對於100%的測試點,1<=N,M,T,K<=4000

v<=100N,M,K,T均為整數

題解:

看完題目,可發現這個題目像數塔,但是因為有速度,在一行可以左右移,所以可推出狀態轉移方程f[i,j]=max{f[i,j-k]~f[i,j+k],},所以復雜度為i*j*k,看范圍,會超時。再觀察題目,發現對於每個上一行,在一個區間內找一個最大值,且一格一格移動,聯想到‘掃描’,可以用單調隊列優化。先處理出k范圍的隊列(里面畢竟要先有數吧)(預處理)之后才能進行刪頭處理。再對第i行每個狀態進行處理(1~j)可用滾動數組。此處單調隊列與導彈攔截的優化不同,這是一個一個移的

var
 m1,s,n,m,i,k,j,tt,x,y,z,t,h,max,l:longint;
 ans:int64;
 q,f,dp,id:array[-10..100000]of longint;//q隊列,id下標數組,dp滾動數組(協助存上一層數),f答案數組
 a:array[-1..4000,-1..4000]of longint;
begin
 readln(n,m,s,L);
  for i:=1 to s do
   begin
     readln(x,y,z);
     a[x,y]:=z;
   end;

   for i:=1 to m do  f[i]:=a[1,i];

    for i:=2 to n do
     begin
     h:=1;t:=1; q[1]:=f[1];id[1]:=1;
      for j:=2 to l do
      begin

             while (f[j]>q[t])and(h<=t)do dec(t);
                  inc(t); q[t]:=f[j];id[t]:=j;

      end;
       k:=l;//dp[1]=q[h]+a[1,i];
       for j:=1 to m do //you wrong here這里我調了好久,本來以為1已經計算過了,但不知道為什么沒有,2改成1 就過了,所以dp盡量用記憶化
        begin
         if k+1<=m then
          begin
            inc(k);
            while (q[t]<f[k])and(h<=t) do dec(t);
            inc(t); q[t]:=f[k];id[t]:=k;
          end;
             begin  while id[h]<j-l do inc(h);
                   dp[j]:=q[h]+a[i,j];
             end;
        end;
     for j:=1 to m do
      begin
        f[j]:=dp[j];
        if max<f[j] then max:=f[j];
      end;
    end;

     writeln(max);
end.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM