POJ 1821 單調佇列優化DP

2022-05-24 04:24:13 字數 1724 閱讀 4735

題意:

有一道線性籬笆由n個連續的木板組成。有k個工人,你要叫他們給木板塗色。每個工人有3個引數:l 表示 這個工人可以塗的最大木板數目,s表示這個工人站在哪一塊木板,p表示這個工人每塗乙個木板可以得到的錢。要注意的是,工人i可以選擇不塗任何木板,否則,他的塗色區域必須是連續的一段,並且s[i]必須包含在內。 最後還有,每塊木板只能被塗一次。 

思路:第一眼,水題~dp[i][j]表示第i個人刷的最後一面牆是j時的最大獲利

一看資料範圍,我水了。。。

怎麼優化呢?

dp[i][j]含義同上

dp[i][j]=max(dp[i-1][k]+(j-k)*p[i])    j-l[i]+1<=k+1<=s[i]

dp[i][j]=max(dp[i-1][j],dp[i][j-1],dp[i][j])//第i個人不刷,第j面牆不刷

其中第二個方程轉移時0(1)的,不用優化了,第乙個方程轉移時0(n)的,我們要想辦法優化它

優化方程一般就是恒等變形+找規律

dp[i][j]=max(dp[i-1][k]-k*p[i])+j*p[i]

其中j*p[i]在i,j兩重迴圈中相當於常數,所以,對於狀態dp[i][j]只要維護dp[i-1][k]-k*p[i]的最大值即可

就用單調佇列維護

單調佇列維護過程:**自lyd神犇的部落格)

單調佇列具體的做法是:最外層迴圈為i,首先把j=1~s[i]-1轉移完(因為它不涉及第三個轉移),然後把(j-l[i]<=k<=s[i]-1)的決策點的f[i-1,k]-p[i]*k依次入隊建立「入隊早晚時間遞增,f[i-1,k]-p[i]*k的值遞減」的單調佇列,接下來迴圈j=s[i]~s[i]+l[i]-1,進行這三個轉移(第三個轉移只需要用隊首元素),其中每次需要把隊首超出長度限制的決策點出隊;最後把剩下的到n迴圈完,只需要前兩個轉移。

自己的單調佇列寫錯了,不停地wa,借鑑了lyd神犇的步驟,嘿嘿,ac了~

view code

1 #include 2 #include 3 #include 4 #include 5 #include 6

7#define n 120

8#define m 17000910

using

namespace

std;

1112

struct

re13

re[n];

1617

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

],n,k;

1819 inline bool cmp(const re &a,const re &b)

2023

24void

read()

2535}36

37void

go()

3850

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

5156

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

]);57}58

int ans=0;59

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

60 printf("

%d\n

",ans);61}

6263

intmain()

6470

return0;

71 }

POJ1821 Fence 單調佇列優化DP

題意 給長度為n的木板,k個工人,每個工人要麼不粉刷,或者選擇乙個包含木板si,長度不超過li的連續的一段木板粉刷,每粉刷一塊得到pi的報酬,問如何安排工人使得總報酬最大?思路 可以按si給工人排序,這樣我們就可以按照順序依次安排工人。設f i j 表示到第i個工人,刷到前j塊木板的最大報酬,三種情...

單調佇列1006 POJ 1821 Fence

題意 有乙個長度為n的牆壁,有k個粉刷匠來刷牆 每個粉刷匠都有三種屬性 1.最大刷牆的距離 必須是連續的區間 2.刷每塊牆的 3.初始位置 刷牆的區間必須包含初始位置 求這幾個粉刷匠刷長度為n的牆最多賺多少錢 思路 我們考慮 dp i j 為前i個粉刷匠刷前j面牆最多的賺的錢 我們考慮對於每個粉刷匠...

POJ2373 單調佇列優化DP

這道題調了我一天.呃.開始很多地方沒注意.傳說中樓教主的男人八題搞定一道.這道題是一道典型的dp題.但直接做時死超的.所以要用單調佇列來優化.關於最基礎的單調佇列.我前一篇文章已經說了.所以直接分析本題.題意是說有乙個直線的山脊.噴泉是乙個在中間向兩邊同時噴的.最近噴a.最遠b.同時山脊上有牛.每只...