uva1427 - Parade 单调队列 维护递减数列

Panagola, The Lord of city F likes to parade very much. He always inspects his city in his car and enjoys the welcome of his citizens. City F has a regular road system. It looks like a matrix withn + 1 west-east roads andm + 1 north-south roads. Of course, there are(n + 1)×(m + 1) road crosses in that system. The parade can start at any cross in the southernmost road and end at any cross in the northernmost road. Panagola will never travel from north to south or pass a cross more than once. Citizens will see Panagola along the sides of every west-east road. People who love Panagola will give him a warm welcome and those who hate him will throw eggs and tomatoes instead. We call a road segment connecting two adjacent crosses in a west-east road a ``love-hate zone". Obviously there arem love-hate zones in every west-east road. When passing a love-hate zone, Panagola may get happier or less happy, depending on how many people love him or hate him in that zone. So we can give every love-hate zone a ``welcome value" which may be negative, zero or positive. As his secretary, you must make Panagola as happy as possible. So you have to find out the best route --- of which the sum of the welcome values is maximal. You decide where to start the parade and where to end it.

When seeing his Citizens, Panagola always waves his hands. He may get tired and need a break. So please never make Panagola travel in a same west-east road for more thank minutes. If it takesp minutes to pass a love-hate zone, we say the length of that love-hate zone isp . Of course you know every love-hate zone's length.

The figure below illustrates the case in sample input. In this figure, a best route is marked by thicker lines.

\epsfbox{p4327.eps}

Input 

There are multiple test cases. Input ends with a line containing three zeros.


Each test case consists of n + 3 lines.

The first line contains three integers: n ,m andk .(0 < n$ \le$100, 0 <m$ \le$10000, 0$ \le$k$ \le$3000000)

The next n + 1 lines stands for n + 1 west-east roads in north to south order. Each line containsm integers showing the welcome values of the road'sm love-hate zones, in west to east order.

The last n + 1 lines also stands for n + 1 west-east roads in north to south order. Each line containsm integers showing the lengths (in minutes) of the road'sm love-hate zones, in west to east order.

Output 

For each test case, output the sum of welcome values of the best route. The answer can be fit in a 32 bits integer.

Sample Input 

2 3 2 
7 8 1 
4 5 6 
1 2 3 
1 1 1 
1 1 1 
1 1 1 
0 0 0

Sample Output 

27

  每条横路有高兴值,可以从最下面任意一个路口出发,到最上面任意一个路口结束,问得到最大高兴值是多少。

  假设l[i][j]为从左边(也包括从下面)到(i,j)的最大值,r[i][j]代表从右边(也包括从下面)到(i,j)的最大值。dp[i][j]=max(l[i][j],r[i][j])。如果算每个l,r都横着扫描一遍的话,复杂度O(N*M^2),会超时。l[i][j]=dp[i+1][k]+s[k][j](k到j高兴值之和),k<=j。若设sum[i][j]为第i行从0到j高兴值的和,那么l[i][j]=max(dp[i+1][k]+sum[j]-sum[k]),k<=j。也就是找j之前dp[i+1][k]-sum[k]最大的。那我们用一个队列,从左到右扫描,j从0到M的扫描过程中,如果dp[i+1][j]-sum[j]比队列最后一个元素的的这个值大,就把最后一个元素删掉。因为前面的明显时间又长,那个值又小,一点用没有。接着把j值加到队尾。这个队列是个递减数列,尽量选队列前的数。但如果队首元素的到j的时间超过K了,肯定就不能选了,删掉。如果时间不超过K,就选队首元素。这样O(M)的时间扫一遍就可以求出行的l值。求r值也是一样的方法,倒着扫一遍,r[i][j]=max(dp[i+1][j]+sum[k]-sum[j]),k>=j。这样时间就是O(N*M)。

  另外dp数组不用开二维,一维就行了。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<sstream>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define INF 0x3f3f3f3f
#define MAXN 110
#define MAXM 10010
#define eps 1e-9
#define pi 4*atan(1.0)
#define pii pair<int,int>
using namespace std;
int N,M,K;
int sum[MAXN][MAXM],Time[MAXN][MAXM],dp[MAXM],q[MAXM],d[MAXM];
int main(){
    freopen("in.txt","r",stdin);
    while(scanf("%d%d%d",&N,&M,&K),N||M||K){
        memset(sum,0,sizeof(sum));
        memset(Time,0,sizeof(Time));
        for(int i=0;i<=M;i++) dp[i]=0;
        int t;
        for(int i=1;i<=N+1;i++)
            for(int j=1;j<=M;j++){
                scanf("%d",&t);
                sum[i][j]=sum[i][j-1]+t;
            }
        for(int i=1;i<=N+1;i++)
            for(int j=1;j<=M;j++){
                scanf("%d",&t);
                Time[i][j]=Time[i][j-1]+t;
            }
        for(int i=N+1;i>=1;i--){
            for(int j=0;j<=M;j++) d[j]=dp[j];    //相当于d[j]=dp[i+1][j]
            int front=0,rear=-1;                 //判断左边最大
            for(int j=0;j<=M;j++){
                t=d[j]-sum[i][j];
                while(front<=rear&&t>=d[q[rear]]-sum[i][q[rear]]) rear--;
                q[++rear]=j;
                while(front<=rear&&Time[i][j]-Time[i][q[front]]>K) front++;
                t=d[q[front]]-sum[i][q[front]]+sum[i][j];
                dp[j]=max(dp[j],t);
            }
            front=0;                              //判断右边最大
            rear=-1;
            for(int j=M;j>=0;j--){
                t=d[j]+sum[i][j];
                while(front<=rear&&t>=d[q[rear]]+sum[i][q[rear]]) rear--;
                q[++rear]=j;
                while(front<=rear&&Time[i][q[front]]-Time[i][j]>K) front++;
                t=d[q[front]]+sum[i][q[front]]-sum[i][j];
                dp[j]=max(dp[j],t);
            }
        }
        int ans=-INF;
        for(int i=0;i<=M;i++) ans=max(ans,dp[i]);
        printf("%d\n",ans);
    }
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值