poj1821 Fence(单调队列优化dp)

地址

一排N个木板,M个工匠站在不同位置$S_i$,每个人可以粉刷覆盖他位置的、最长长度为$L_i$木板段,每刷一个有$P_i$报酬。同一木板只刷一次。求最大报酬。


根据每个人的位置dp,设$f[i][j]$为第$i$个人刷前$j$个木板的最大报酬。$j<s[i]$表示不刷。

那就有

$f[i][j]=max{f[i-1][k]+(j-k)*p[i]}   $       $   (s[i]≤j<s[i]+L[i] , s[i]-L[i]≤k<j)$

然后对于每行,相当于j从前面$l[i]$块选。拆开来。

$f[i][j]=max{f[i-1][k]-k*p[i]}+j*p[i]  $       $   (s[i]≤j<s[i]+L[i] , s[i]-L[i]≤k<j)$

然后里面跟决策点k有关,在每行$s[i]$前面$l[i]$个位置把决策塞进一个$f[i-1][k]-k*p[i]$单调减,$k$单调增的单调队列里,然后每行取队头,及时排除、转移即可。

代码写繁了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 typedef long long ll;
 8 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;}
 9 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;}
10 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
11 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
12 template<typename T>inline T read(T&x){
13     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
14     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
15 }
16 const int N=35000+7;
17 int f[2][N],q[N];
18 struct hinanawitenshi{
19     int p,l,s;
20 }a[107];
21 int n,m,tmp,l,r;
22 inline char cmp(hinanawitenshi A,hinanawitenshi B){return A.s<B.s;}
23 inline int F(int k,int i,int now){return f[now^1][k]-k*a[i].p;}
24 
25 int main(){//freopen("tmp.in","r",stdin);freopen("tmp.out","w",stdout);
26     read(n),read(m);
27     for(register int i=1;i<=m;++i)read(a[i].l),read(a[i].p),read(a[i].s);
28     sort(a+1,a+m+1,cmp);
29     for(register int i=1,now=1;i<=m;++i,now^=1){
30         tmp=0;l=1,r=0;
31         for(register int j=1;j<a[i].s;++j)f[now][j]=f[now^1][j];
32         for(register int k=_max(a[i].s-a[i].l,0);k<a[i].s;++k){
33             while(l<=r&&F(k,i,now)>=F(q[r],i,now))--r;
34             q[++r]=k;
35         }
36         for(register int j=a[i].s;j<=_min(a[i].s+a[i].l-1,n);++j){
37             while(l<=r&&q[l]<j-a[i].l)++l;
38             f[now][j]=_max(f[now^1][j],F(q[l],i,now^1)+j*a[i].p);
39             MAX(tmp,f[now][j]);
40         }
41         for(register int j=a[i].s+a[i].l;j<=n;++j)f[now][j]=_max(f[now^1][j],tmp);//MISTAKE:之后的状态忘转移了。
42     }
43     printf("%d
",f[m&1][n]);
44     return 0;
45 }
原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/10453352.html