hdu 3630 Crystal mine

来源:互联网 发布:mysql下载安装教程 编辑:程序博客网 时间:2024/04/28 04:17

Crystal mine

Time Limit: 5000/1500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 528    Accepted Submission(s): 86


Problem Description
Legends always begin with the sentence “Long long ago......”
Long long ago, there is a kingdom. The border of this kingdom is rectangular, and some lakes in it. Old king divides land to N * M areas. So, we can regard this kingdom as a matrix. Every element of matrix is an area. This kingdom is famous for crystal mine, because every land contains an ocean of crystal underground, except lakes.
Now, the old king wants to build a large rectangular mine field in a rectangular range which is decide by him. What’s more, he wants to build a special area in mine field, which can produce crystal manyfold. Notice that mine field can't contain lakes. Unfortunately, the old king is too old to remember something. He always asks his adviser this question with different range.
Adviser is tired of answering those questions day by day. So, you are assigned to solve this problem. You get the kingdom map, and the amount of crystal of every area (as A[][]) has been marked on this map. You should find out the best plan to build this mine field which can produce most crystal. Old king never care the details of plan. The only thing he wants know is the number of crystal the mine field can produce.
 

Input
There are several test cases in the input file.
The first line of input file contains a number T, representing the number of test cases. For each test case:
First line contains four integers separated by a single blank, N (1 <= N <= 150), M (1 <= M <= 150), Q (1<= Q <= 200), S (1 <= S <= 10). The size of matrix is N * M. Q indicates the number of questions of old king. S indicates that, if you set the special area in (i,j), (i,j) will produce S * A[i][j] instead of A[i][j].
The following N lines, each line contains M number, the j-th number of i-th line represent A[i][j] (-1 <= A[i][j] < 100 ). Number -1 indicates that, this area is a lake. Otherwise A[i][j] indicates the amount of crystal in this area.
Following Q line, each line contains four integers p, q, x, y. (1 <= p <= x <= N, 1 <= q <= y <= M) indicating the rectangular range of this question is from (p,q) to (x,y). (p,q) is upper left corner of range, and (x,y) is lower right corner of range.
 

Output
For each test case, first line should contains “Case #: ”, ”#”is case number (starting from 1). Each of the following Q line contains a number indicating the answer of question.
Look at sample output for more details. There is a blank line between two consecutive test cases.
 

Sample Input
14 4 3 21 -1 0 31 1 2 02 1 0 -11 4 6 11 1 1 11 1 3 31 3 3 4
 

Sample Output
Case 1:298
题意:给你一个地图 再给你一个矩阵范围 让你在这个矩阵中找到一个不包含-1的子矩阵 且这个子矩阵的和+S*(max-1) 最小 (max 为这个子矩阵的和的最大值)
思路:用最大子矩阵方法枚举出满足条件的矩阵 预处理后能直接对子矩阵求和 然后用二维RMQ求最大值 然后更新ans
感想:其实思路并不难 题目也并不是太难 不过坑了我和我的老大几天额 ╮(╯▽╰)╭ 我们的复杂度降到O(n^3)了 但还是TLE 好蛋疼 感谢网友ice_crazy 我们是从他的代码中找到了是什么卡了我们的时间 二维RMQ时求log(n)/log(2) 这个打一个表就够了 因为不打表的话就会算O(n^3)次 会很拖时间的  
#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;const int maxn = 155;int a[maxn][maxn];int mp[maxn][maxn];int power[maxn];int ssum[maxn][maxn];                       // 对二维数组预处理 方便求子矩阵和int dp[maxn][maxn][9][9];int h[maxn][maxn],le[maxn][maxn],ri[maxn][maxn];int n,m,q,ans,sum,s;int maxx(int xx,int yy){    return xx>yy?xx:yy;}void init_rmq(){    for(int i=0; (1<<i)<=n; i++)    {        for(int j=0; (1<<j)<=m; j++)        {            if(i==0 && j==0)                continue;            for(int row=1; row+(1<<i)-1<=n; row++)            {                for(int col=1; col+(1<<j)-1<=m; col++)                {                    if(i==0)                    {                        dp[row][col][i][j] =                            maxx(dp[row][col][i][j-1],dp[row][col+(1<<(j-1))][i][j-1]);                    }                    else                    {                        dp[row][col][i][j] =                            maxx(dp[row][col][i-1][j],dp[row+(1<<(i-1))][col][i-1][j]);                    }                }            }        }    }}int query(int x1,int y1,int x2,int y2){    int kx=power[x2-x1+1];    int ky=power[y2-y1+1];    int m1=dp[x1][y1][kx][ky];    int m2 = dp[x2-(1<<kx)+1][y1][kx][ky];    int m3 = dp[x1][y2-(1<<ky)+1][kx][ky];    int m4 = dp[x2-(1<<kx)+1][y2-(1<<ky)+1][kx][ky];    return maxx( maxx(m1,m2), maxx(m3,m4) );}void left(int hang)                   // 向左扩展{    int i,j;    h[hang][0]=-2;    for(i=1; i<=m; i++)    {        if(h[hang][i]>0)        {            le[hang][i]=1;            while(h[hang][i-le[hang][i]]>=h[hang][i])            {                le[hang][i]+=le[hang][i-le[hang][i]];            }        }    }}void right(int hang)                  // 向右扩展{    int i,j;    h[hang][m+1]=-2;    for(i=m; i>=1; i--)    {        if(h[hang][i]>0)        {            ri[hang][i]=1;            while(h[hang][i+ri[hang][i]]>=h[hang][i])            {                ri[hang][i]+=ri[hang][i+ri[hang][i]];            }        }    }}void init_maxarrey()                    // 对矩阵做求最大子矩阵的预处理  {    int i,j;    for(i=1; i<=n; i++)    {        for(j=1; j<=m; j++)        {            if(mp[i][j]>0) h[i][j]=h[i-1][j]+1;            else h[i][j]=0;        }        left(i);        right(i);    }}void solve(int u1,int v1,int u2,int v2){    int i,j,k,ss;    int xx1,xx2,yy1,yy2,temps;    ans=0;    for(i=u1; i<=u2; i++)    {        for(j=v1; j<=v2; j++)        {            if(h[i][j]>=0)               // 这里的判断条件不要加错了  我开始加的是 h[i][j]-h[u1][j]>=0 不能这么加             {                xx1=maxx(i-h[i][j]+1,u1);                yy1=maxx(j-le[i][j]+1,v1);                xx2=i;                yy2=j+ri[i][j]-1<v2?j+ri[i][j]-1:v2;                temps=query(xx1,yy1,xx2,yy2);                ss=ssum[xx2][yy2]-ssum[xx2][yy1-1]-ssum[xx1-1][yy2]+ssum[xx1-1][yy1-1]+temps*(s-1);                if(ans<ss) ans=ss;            }        }    }}int main(){    int i,j,t,t1,k;    for(i=1;i<=150;i++)                 // 打表很重要    {        power[i]=log(double(i))/log(2.0);    }    scanf("%d",&t);    for(k=1; k<=t; k++)    {        scanf("%d%d%d%d",&n,&m,&q,&s);        memset(ssum,0,sizeof(ssum));        for(i=1; i<=n; i++)        {            for(j=1; j<=m; j++)            {                scanf("%d",&a[i][j]);                dp[i][j][0][0]=a[i][j];                ssum[i][j]=a[i][j]+ssum[i-1][j]+ssum[i][j-1]-ssum[i-1][j-1];                if(a[i][j]>=0) mp[i][j]=1;                else mp[i][j]=-1;            }        }        init_rmq();        init_maxarrey();        if(k>1) printf("\n");        printf("Case %d:\n",k);        while(q--)        {            int x1,y1,x2,y2;            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);            solve(x1,y1,x2,y2);            printf("%d\n",ans);        }    }    return 0;}


原创粉丝点击