1. 程式人生 > >POJ 1821 Fence (單調佇列優化DP)

POJ 1821 Fence (單調佇列優化DP)

題目大意:有k個工人,有一排n個磚頭,現在要給磚頭染色,每個工人要麼不染色,要麼選擇一個包含$s_{i}$的,長度不大於$l_{i}$的區域進行染色,然後他們會獲得$len\cdot p_{i}$的報酬,求使所有工人總報酬最大的方案,輸出最大報酬

定義$f[i][j]$表示已經遍歷到了第i個工人,遍歷到了第j塊磚頭的最大報酬

顯然$f[i][j]=max(f[i-1][j],f[i][j-1],f[i-1][k]+(j-k)p_{i})$

展開$f[i-1][k]+(j-k)p_{i}=f[i-1][k]-k\cdot p_{i}+j\cdot p_{i}$,發現$f[i-1][k]-k\cdot p_{i}$具有單調性,用單調佇列優化即可

注意能使用佇列優化轉移的區間必須包含$s_{i}$

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define N1 16010
 5 #define M1 105
 6 #define ll long long 
 7 using namespace std;
 8 
 9 int K,n;
10 ll f[2][N1];
11 int que[N1];
12 struct node{int l,w,s;}a[M1];
13 int cmp(node s1,node s2)
14 {return s1.s<s2.s;} 15 16 int main() 17 { 18 while(scanf("%d%d",&n,&K)!=EOF) 19 { 20 int now=1,pst=0; 21 for(int i=1;i<=K;i++) 22 scanf("%d%d%d",&a[i].l,&a[i].w,&a[i].s); 23 sort(a+1,a+K+1,cmp); 24 for(int i=1;i<=K;i++)
25 { 26 int hd=1,tl=0; 27 memset(f[now],0,sizeof(f[now])); 28 if(a[i].s-a[i].l<=0&&0<a[i].s) que[++tl]=0; 29 for(int j=1;j<=n;j++) 30 { 31 while(hd<=tl&&(j-que[hd]>a[i].l)) 32 hd++; 33 f[now][j]=max(max(f[pst][j],f[now][j-1]),(hd<=tl&&j>=a[i].s)?(f[pst][que[hd]]+1ll*a[i].w*(j-que[hd])):0ll); 34 if(j<a[i].s-a[i].l||j>=a[i].s) continue; 35 while(hd<=tl&&f[pst][j]-a[i].w*j>=f[pst][que[tl]]-a[i].w*que[tl]) 36 tl--; 37 que[++tl]=j; 38 }swap(now,pst); 39 } 40 printf("%lld\n",f[pst][n]); 41 memset(f,0,sizeof(f)); 42 memset(a,0,sizeof(a)); 43 memset(que,0,sizeof(que)); 44 } 45 return 0; 46 }