poj3926 parade (单调队列+dp)

题意:有n行路,每行路被分成m段,每一段有长度和权值,要求从最下面一行走到最上面一行某个位置,可以从相邻两行的同一列交点往上走,并且在同一行走的长度要<=K,求走过的最大权值

设f[i][j]为到第i行,第j个交点的最大值
设sumvalue[i][j,k]为第i行从第j个交点到第k个交点经过道路的权值之和
设sumtime[i][j,k]为第i行从第j个交点到第k个交点经过道路的长度之和
则f[i][j]=max{
f[i-1][k]+sumvalue[i][k,j] ,k<=j且sumtime[i][k,j]<=K
f[i-1][k]+sumvalue[i][j,k] ,k>j且sumtime[i][j,k]<=K
}

以第一个方程为例,单调队列记某行i∈[k,j]的f[][i]+sumvalue[][i..j]的最大值即可

其中,在j++的时候,由于要给所有数加上val[][j]的值,我们就假装大家一起
减掉了val[][j]的值,只给要新进的f[][j]+val[][j]减掉sumvalue[][0..j]即可
(最后给f值的时候别忘了加回来)

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define LL long long int
 5 using namespace std;
 6 const int maxn=110,maxm=10010;
 7 
 8 int rd(){
 9     int x=0,neg=1;char c=getchar();
10     while(c<'0'||c>'9') {if(c=='-') neg=-1;c=getchar();}
11     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
12     return x*neg;
13 }
14 
15 int N,M,K;
16 int val[maxm][maxn],len[maxm][maxn],head,tail;
17 LL f[maxm][maxn],q[maxm][2],ans;
18 
19 inline void insert(LL x,int y){
20     for(int i=tail;i>=head;i--){
21         if(q[i][0]>x){
22             tail=i+1;q[tail][0]=x;q[tail][1]=y;
23             return;
24         }
25     }tail=head;q[tail][0]=x;q[tail][1]=y;
26 }
27 
28 int main(){
29     int i,j,k;
30     //freopen("3926.in","r",stdin);
31     while(1){
32         N=rd(),M=rd(),K=rd();if(!N) break;
33         for(i=1;i<=N+1;i++){
34             for(j=1;j<=M;j++) val[j][i]=rd();
35         }for(i=1;i<=N+1;i++){
36             for(j=1;j<=M;j++) len[j][i]=rd();
37         }
38         memset(f,0,sizeof(f));ans=0;
39         for(i=1;i<=N+1;i++){
40             LL sv=0,st=0;
41             tail=head=1;memset(q,0,sizeof(q));
42             for(j=0;j<=M;j++){
43                 sv+=val[j][i],st+=len[j][i];
44                 insert(f[j][i-1]-sv,st);
45                 while(st-q[head][1]>K) head++;
46                 f[j][i]=q[head][0]+sv;
47             }
48             sv=0;st=0;
49             tail=head=1;memset(q,0,sizeof(q));
50             for(j=M;j>=0;j--){
51                 sv+=val[j+1][i],st+=len[j+1][i];
52                 insert(f[j][i-1]-sv,st);
53                 while(st-q[head][1]>K) head++;
54                 f[j][i]=max(f[j][i],q[head][0]+sv);
55             }
56         }
57         for(j=0;j<=M;j++) ans=max(ans,f[j][N+1]);
58         printf("%d\n",ans);
59     }
60     
61 }

猜你喜欢

转载自www.cnblogs.com/Ressed/p/9376995.html