LA 4327 多段图

题目链接:https://vjudge.net/contest/164840#problem/B

题意:

从南往北走,横向的时间不能超过 c;

横向路上有权值,求权值最大;

分析:

n<=100,m<=10000

数据范围很大了,基本上要n*m;

分析每个交叉路口,每个交叉路口,可以从下一行的左边,或者下一行的右边过来;

那么这个交叉路口就是max(L[j],R[j]);

怎么得到,某一个交叉路口从左边来,可以有哪些点呢? 不可能循环跑一遍(m的范围);

就用了一个Q双端队列来维护;

怎么得到,从哪个点上来最优呢? 在这个队列中的点也不能循环跑一遍;

还是利用这个队列;维护他这个队列是单调队列就好了,

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 #define LL long long
 6 
 7 const int maxn = 105;
 8 const int maxm = 10100;
 9 LL f[maxn][maxm],t[maxn][maxm],L[maxm],R[maxm],n,m,c,d[maxn][maxm];
10 
11 deque<int> Q;
12 int Lfunc(int j,int i) {
13     return d[i-1][j] - f[i][j];
14 }
15 
16 int Rfunc(int j,int i) {
17     return d[i-1][j] + f[i][j];
18 }
19 
20 int main() {
21     while(scanf("%lld %lld %lld",&n,&m,&c)==3&&n) {
22         for(int i=1; i<=n+1; i++)
23             for(int j=0; j<=m; j++) {
24                 if(!j) f[i][j] = 0;
25                 else {
26                     scanf("%lld",&f[i][j]);
27                     f[i][j]+=f[i][j-1];
28                 }
29             }
30 
31 
32         for(int i=1; i<=n+1; i++)
33             for(int j=1; j<=m; j++) {
34                 if(!j) t[i][j] = 0;
35                 else {
36                     scanf("%lld",&t[i][j]);
37                     t[i][j]+=t[i][j-1];
38                 }
39             }
40 
41 
42         for(int i=0; i<=m; i++)
43             d[0][i] = 0;
44 
45         for(int i=1; i<=n+1; i++) {
46             L[0] = d[i-1][0];
47             Q.clear();
48             Q.push_back(0);
49             for(int j=1; j<=m; j++) {
50                 while(!Q.empty()&&t[i][j]-t[i][Q.front()]>c) {
51                     Q.pop_front();
52                 }
53                 L[j] = d[i-1][j];   //从左到达 j 的最优值
54                 if(!Q.empty()) L[j] =max(L[j],Lfunc(Q.front(),i)+f[i][j]);
55                 while(!Q.empty()&&Lfunc(Q.back(),i)<=Lfunc(j,i)) Q.pop_back();
56                 Q.push_back(j);
57             }
58             
59             
60             R[0] = d[i-1][m];
61             Q.clear();
62             Q.push_back(m);
63             for(int j=m-1; j>=0; j--) {
64                 while(!Q.empty()&&t[i][Q.front()]-t[i][j]>c) Q.pop_front();
65                 R[j] = d[i-1][j];
66                 if(!Q.empty()) R[j] = Rfunc(Q.front(),i)-f[i][j];
67                 while(!Q.empty()&&Rfunc(Q.back(),i)<=Rfunc(j,i)) Q.pop_back();
68                 Q.push_back(j);
69             }
70             for(int j=0; j<=m; j++)
71                 d[i][j] = max(L[j],R[j]);
72         }
73         
74         LL res;
75         for(int i=0; i<=m; i++) {
76             if(!i) res=d[n+1][i];
77             else res = max(d[n+1][i],res);
78         }
79         printf("%lld
",res);
80     }
81     return 0;
82 }
View Code
原文地址:https://www.cnblogs.com/TreeDream/p/6896581.html