hdu Parade(单调队列优化 dp)

来源:互联网 发布:任我行 知乎 编辑:程序博客网 时间:2024/05/16 15:53

Parade

Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 504 Accepted Submission(s): 209


Problem Description
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 with n+1 west-east roads and m+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 are m 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 than k minutes. If it takes p minutes to pass a love-hate zone, we say the length of that love-hate zone is p. 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.


Input
There are multiple test cases. Input ends with a line containing three zeros.
Each test case consists of 2×n + 3 lines.

The first line contains three integers: n, m and k.(0<n<=100,0<m<=10000, 0<=k<=3000000)

The next n+1 lines stands for n + 1 west-east roads in north to south order. Each line contains m integers showing the welcome values of the road’s m 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 contains m integers showing the lengths (in minutes) of the road's m 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 27 8 14 5 61 2 31 1 11 1 11 1 10 0 0

Sample Output
27

Source
2008 Asia Regional Beijing

Recommend
gaojie
 
 
对现在的我来说,这是一道很难的题
思路还是挺简单的,状态和转移方程都很好找,
转移时就是三种情况,左,右,下。关键在优化上。
因为如果每次转移时都用O(n)的时间去搜一遍是超时的,所以我们就思考能不能在O(1)的时间完成
那要怎么做呢?肯定是需要一种对数据的合理的组织方式,即需要依靠一种数据结构来完成
单调队列,用两个单调队列,分别维护每个点左右两边的最大值
单调队列写起来并不麻烦,但这道题由于我写的时候思路不清晰,改了很久,后来全部重写一遍才一次AC了
要注意的几点:
1.当位于行首和行尾时,需要单独处理那两个队列
2.需要考虑当前位置时,不可能有从左边或右边走过来的情况,因为k值很小(题目并不保证k比所有的路花费的时间都大)
3.用队列要pop前一定要记得判这个队列是否为空,否则错都不知道错在哪儿,代码相当难改(竟然可以把队列的大小抛成-1。。)
,在用队列的首或尾元素时,也要记得判队列是否为空
4.在处理单调队列的时候,用了pl,和pr两个记录,我采用的是左闭右开区间,一定要想清楚下标,很容易出错
 
这题的代码在LA上排到了第一版
#include <iostream>#include <cstdio>#include <algorithm>#include <queue>#include <cstring>using namespace std;struct Node{    int value,p;};int sum[105][10005],cost[105][10005];int dp[105][10005];deque <Node> dequel,dequer;int main(){    int n,m,k;    int pl,pr;    while(1){        scanf("%d%d%d",&n,&m,&k);        if(n == 0 && m == 0 && k == 0)  break;        const int total = k;        memset(dp,0,sizeof(dp));        for(int i = 0;i < 105;i++){            sum[i][0] = 0;            cost[i][0]= 0;        }        for(int i = 0;i < n+1;i++){            for(int j = 1;j <= m;j++){                scanf("%d",&sum[i][j]);                sum[i][j] += sum[i][j-1];            }        }        for(int i = 0;i < n+1;i++){            for(int j = 1;j <= m;j++){                scanf("%d",&cost[i][j]);                cost[i][j] += cost[i][j-1];            }        }        for(int i = n;i >= 0;i--){            dequel.clear();dequer.clear();            pl = -1;pr = 1;            for(int j = 0;j <= m;j++){                if(j != m){                    while(pr <= m && total >= cost[i][pr] - cost[i][j]){                        if(dequer.empty()){                            Node tem;                            tem.p = pr;tem.value = dp[i+1][pr]+sum[i][pr++];                            dequer.push_front(tem);                        }                        else{                            while(!dequer.empty()&&(dequer.front().value<dp[i+1][pr]+sum[i][pr]||dequer.front().p<=j)){                                dequer.pop_front();                            }                            Node tem;                            tem.p = pr;tem.value = dp[i+1][pr]+sum[i][pr++];                            dequer.push_front(tem);                        }                    }                    if(pr == j+1 && total < cost[i][pr] - cost[i][j]){                        pr++;                        dequer.clear();                    }                }                else dequer.clear();                if(j != 0){                    if(pl == -1 && total >= cost[i][j]-cost[i][j-1])                        pl = j-1;                    while(pl < j-1 && total < cost[i][j]-cost[i][pl]){                        pl++;                    }                    if(total >= cost[i][j]-cost[i][pl]){                        if(dequel.empty()){                            Node tem;                            tem.p = j-1;tem.value = dp[i+1][j-1]-sum[i][j-1];                            dequel.push_front(tem);                        }                        else{                            while(!dequel.empty() && (dequel.front().value < dp[i+1][j-1]-sum[i][j-1]||dequel.front().p < pl)){                                dequel.pop_front();                            }                        }                        Node tem;                        tem.p = j-1;tem.value = dp[i+1][j-1]-sum[i][j-1];                        dequel.push_front(tem);                    }                    if(pl == j-1 && total < cost[i][j]-cost[i][pl]){                        pl = -1;                        dequel.clear();                    }                }                while(!dequel.empty() && dequel.back().p < pl){                    dequel.pop_back();                }                while(!dequer.empty() && dequer.back().p <= j){                    dequer.pop_back();                }                if(dequel.empty() && dequer.empty()){                    dp[i][j] = dp[i+1][j];                }                else if(dequel.empty()){                    dp[i][j] = dequer.back().value-sum[i][j];                }                else if(dequer.empty()){                    dp[i][j] = dequel.back().value+sum[i][j];                }                else                    dp[i][j] = max(dequel.back().value+sum[i][j],dequer.back().value-sum[i][j]);                dp[i][j] = max(dp[i][j],dp[i+1][j]);            }        }        int ans = dp[0][0];        for(int i = 1;i <= m;i++)            ans = max(ans,dp[0][i]);        printf("%d\n",ans);    }    return 0;}