题目链接: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 }