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 }

 

posted @ 2018-11-30 14:49  guapisolo  阅读(151)  评论(0编辑  收藏  举报