日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

POJ1821 Fence

發布時間:2023/12/2 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 POJ1821 Fence 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

傳送門

這道題是一道很好的單調隊列優化DP的例子。

題目大意是有n個工人,每個人可以粉刷一段長度不超過l[i]的墻,如果一個人粉刷了那么他必須要粉刷第s[i]塊墻,一個人粉刷一塊墻能得到p[i]的錢,求所有工人得到的錢的最大值。

我們首先把所有工人按s[i]排序,這樣方便我們線性DP。

考慮DP,用dp[i][j]表示前i個工人刷j塊的得到的錢的最大值,那么我們分類討論,首先是一個人不刷和一塊墻不刷的情況,那么就有dp[i][j] = max(dp[i-1][j],dp[i][j-1]);

之后,我們考慮這個工人刷墻的情況。因為這個人必須要刷s[i],那這個人的轉移必然是從s[i] - l[i] ~ s[i]這一段轉移過來的。否則的話就成了不合法情況。那么就有dp[i][j] = max{dp[i-1][k] + (j - k) * p[i]} (s[i] - l[i] <= k <= s[i])

這個式子我們樸素的做法是先枚舉i,對于每一個工人i,枚舉它粉刷的塊數j,之后再枚舉轉移的范圍。不過這樣會超時,我們考慮優化。我們發現如果把j,k分離出來,那么對于每一個j(狀態),它對應的j * p[i]是一個定值,只有內部的式子隨著k(決策)的變化而改變,而且其實對于每一個j,有很大一部分的可選取的決策區間是重復的。

說到這里,我們就想到用單調隊列維護啦!!那么我們的想法就是,對于每一個工人,我們首先把s[i] - l[i] ~ s[i]這一段區間之內的所有決策壓入單調隊列,之后隨著j的增加,所能選取的k的區間左端點隨之變大。也就是說實際上,我們只要維護一段左端點變大,右端點不動的區間最大值就可以了。

所以一般來說,單調隊列優化DP的套路就是,如果一個DP方程能被拆成每一個狀態都是從一個決策區間中選取最優的轉移,然后決策區間隨著狀態變化左右端點變化,而且有大量重復,我們就可以先拆分式子,拆成內層只與決策有關,這樣直接用單調隊列維護決策的極值,就省去了一層循環,優化了時間。

看一下代碼。

#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<set> #include<queue> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n')using namespace std; typedef long long ll; const int M = 10005; const int INF = 1000000009;int read() {int ans = 0,op = 1;char ch = getchar();while(ch < '0' || ch > '9'){if(ch == '-') op = -1;ch = getchar();}while(ch >= '0' && ch <= '9'){ans *= 10;ans += ch - '0';ch = getchar();}return ans * op; }struct worker {int l,p,s;bool operator < (const worker &g) const{return s < g.s;} }a[105];int n,k,dp[105][20005],q[20005],head,tail;int calc(int i,int x) {return dp[i-1][x] - x * a[i].p; }int main() {n = read(),k = read();rep(i,1,k) a[i].l = read(),a[i].p = read(),a[i].s = read();sort(a+1,a+1+k);rep(i,1,k){head = 1,tail = 0;rep(j,max(0,a[i].s-a[i].l),a[i].s-1){while(head <= tail && calc(i,q[tail]) < calc(i,j)) tail--;q[++tail] = j;}rep(j,1,n){dp[i][j] = max(dp[i-1][j],dp[i][j-1]);if(j >= a[i].s){while(head <= tail && q[head] < j - a[i].l) head++;if(head <= tail) dp[i][j] = max(dp[i][j],calc(i,q[head]) + j * a[i].p);}}}printf("%d\n",dp[k][n]);return 0; }

?

轉載于:https://www.cnblogs.com/captain1/p/9929440.html

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的POJ1821 Fence的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。