單調佇列優化DP

2022-05-06 22:09:16 字數 1426 閱讀 9959

這段時間在重溫dp,發現dp中有很大很重要的一塊區域是關於dp優化的,於是來和大家分享一下各種dp優化方法,下面講一下單調佇列優化dp

首先來重溫下什麼是單調佇列,在單調佇列中,每個元素的決策時間單調增而它的決策單調更劣,這就顯然可以明白,最優決策永遠在隊首。

如果對上面基礎單調佇列不了解,可以先做【poj2823】sliding window 這道題目體會一下再回來看後面的重點,這裡就不再贅述了。

在單調佇列中,當區間移動時,在隊頭不停刪除不在區間內的決策,而在隊尾加入決策,在隊尾加入決策前要判斷是否滿足單調性,否則先刪除隊尾決策直到加入決策後能滿足單調性再加入。

下面來一道例題【poj1821】

題意:有k個工人,和長為n的籬笆,現在要給籬笆上色。每個工人坐在si上,他能刷的最大範圍是li,且必須是乙個連續子區間,而且必須過si,他刷完後能獲得pi錢,求總報酬最大值

思路:先設出方程,設 dp[i][j] 表示前i個工人,前 j 個籬笆的最大獲利

那麼dp[i][j]=dp[i-1][j](第i個人不刷)或dp[i][j]=dp[i][j-1] (第i個人不刷第j 塊)

狀態轉移方程是    dp[i][j]  =  max(  dp[i][j]   ,dp[i-1][k]  +  (j-k)*p[i])   j>=s[i],

k=j - l[i]

把加粗的那一段展開得到dp[i-1][k] - k*p[i]+ j*p[i]那麼這樣,前半部分只與決策k有關(除狀態i),這樣的話隨j的增大,k取值範圍下界在增大,上屆不變,所以k越大時存活時間越長,而這時如果還滿足前面加粗式的單增,則不難想到,可以用單調佇列優化,優化後時間複雜度為o(nm)

#include #include #include #include #include #define n 120

#define m 17000

using namespace std;

struct ac

re[n];

int q[m],l[n],r[n],dp[n][17000],n,k;

inline bool cmp(const ac &a,constac &b)

for(int j=re[i].s,tmp;j<=r[i];j++)

for(int j=r[i]+1;j<=n;j++) dp[i][j]=max(dp[i-1][j],dp[i][j-1]);

}int ans=0;

for(int i=1;i<=n;i++) ans=max(ans,dp[k][i]);

printf("%d\n",ans);

}int main()

solve();

}return 0;

}

單調佇列 優化DP

佇列元素保持單調遞增 減 而保持的方式就是通過插隊,把隊尾破壞了單調性的數全部擠掉,從而使佇列元素保持單調。單調佇列的作用 優化dp。許多單調佇列優化的dp可以使複雜度直接降維,下面就以最簡單的一道題為例 在某兩座城市之間有 n 個烽火台,每個烽火台發出訊號都有一定代價。為了使情報準確地傳遞,在連續...

單調佇列優化dp

形如f i max wi的問題都可以用單調佇列優化。例題 板題 注意乙個地方 求完所有的f後 ans不是f n 而是後面的一段字尾的f 注意字尾的左端點。很顯然是rmq問題 計算字首和sum i 對於固定的右端點 i,我們想讓答案最大等價於max,可以用個單調佇列維護。但是隨便乙個資料結構直接on ...

DP 單調佇列優化

使用單調佇列優化的題目具有這樣的特點,他需要我們維持一段區間內的某個最優值,這個區間是隨著遍歷的順序變化的,但是其變化一定具有這樣的特性,也即維持的區間左右端點一定是單調遞增的,而不能出現回流的現象,否則我們在維持佇列單調性過程中剪枝的資料可能是新的區間中的最大值。維持區間最優值的方法有很多,例如靜...