POJ 1821 Fence(单调队列优化DP)

题解

以前做过很多单调队列优化DP的题。

这个题有一点不同是对于有的状态可以转移,有的状态不能转移。

然后一堆边界和注意点。导致写起来就很难受。

然后状态也比较难定义。

dp[i][j]代表前i个人涂完前j个位置的最大收益。

然后转移考虑

第i个人可以不刷。dp[i][j]=dp[i-1][j];

第j个木板可以不刷dp[i][j]=dp[i][j-1];

然后当c[i].s<=j<=s[i]+l[i]-1时

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

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 using namespace std;
 7 const int N=20000;
 8 const int M=210;
 9 int dp[M][N],n,m,q[N],head,tail,ans;
10 struct people{
11     int l,p,s;
12 }c[M];
13 bool cmp(people a,people b){
14     return a.s<b.s;
15 }
16 int read(){
17     int sum=0,f=1;char ch=getchar();
18     while(ch<'0'||ch>'9'){
19         if(ch=='-')f=-1;
20         ch=getchar();
21     }
22     while(ch>='0'&&ch<='9'){
23         sum=sum*10+ch-'0';
24         ch=getchar();
25     }
26     return sum;
27 }
28 int main(){
29     while(scanf("%d%d",&n,&m)!=EOF){
30         memset(dp,0,sizeof(dp));
31         for(int i=1;i<=m;i++){
32             c[i].l=read();c[i].p=read();c[i].s=read();
33         }
34         sort(c+1,c+1+m,cmp);
35         for(int i=1;i<=m;i++){
36             memset(q,0,sizeof(q));
37             head=1;tail=1;
38             for(int j=1;j<=n;j++){
39                 dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
40                 if(j>=c[i].s&&j<=c[i].s+c[i].l-1){
41                     while(head<=tail&&q[head]<j-c[i].l)head++;
42                     if(head>tail)continue;
43                     dp[i][j]=max(c[i].p*j+dp[i-1][q[head]]-c[i].p*q[head],dp[i][j]);
44                 }
45                 if(j<c[i].s){
46                     while(head<=tail&&dp[i-1][j]-c[i].p*j>=dp[i-1][q[tail]]-c[i].p*q[tail])tail--;
47                     q[++tail]=j;
48                 }
49             }
50         }
51         printf("%d\n",dp[m][n]);
52     }
53     return 0;
54 }

猜你喜欢

转载自www.cnblogs.com/Xu-daxia/p/9757131.html