HDU 2888 Check Corners

Problem Description
Paul draw a big m*n matrix A last month, whose entries Ai,j are all integer numbers ( 1 <= i <= m, 1 <= j <= n ). Now he selects some sub-matrices, hoping to find the maximum number. Then he finds that there may be more than one maximum number, he also wants to know the number of them. But soon he find that it is too complex, so he changes his mind, he just want to know whether there is a maximum at the four corners of the sub-matrix, he calls this “Check corners”. It’s a boring job when selecting too many sub-matrices, so he asks you for help. (For the “Check corners” part: If the sub-matrix has only one row or column just check the two endpoints. If the sub-matrix has only one entry just output “yes”.)


【题目分析】
第一个结果是比较难的。但是第二个答案是比较简单的,我们可以比较一下最大值和四个角上的值就可以了。
很明显,第一个问题是一个二维的RMQ问题。解法有很多种,比如树套树(线段树&树状数组)甚至平衡树也可以解这道题。
我选择了二维的ST算法。即使十分占空间,但是时间还是比较快的。数组再开大一点点就会MLE.


【代码】

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
inline int max(int a,int b)
{return a>b?a:b;}
int n,m,v[302][302],mx[302][302][9][9];
inline void init()
{
    for (int i=1;i<=n;++i)
        for (int j=1;j<=m;++j)
            mx[i][j][0][0]=v[i][j];
    int k1=(int)(log(double(n))/log(2.0));
    int k2=(int)(log(double(m))/log(2.0));
    for (int i=0;i<=k1;++i)
        for (int j=0;j<=k2;++j)
        if (i!=0||j!=0)
        {
            for (int r=1;r+(1<<i)-1<=n;++r)
            for (int c=1;c+(1<<j)-1<=m;++c)
            {
                if (i==0) mx[r][c][i][j]=max(mx[r][c][i][j-1],mx[r][c+(1<<(j-1))][i][j-1]);
                else mx[r][c][i][j]=max(mx[r][c][i-1][j],mx[r+(1<<(i-1))][c][i-1][j]);
            }
        }

}
inline int query(int r1,int c1,int r2,int c2)
{
    int kr=(int)(log(double(r2-r1+1))/log(2.0));
    int kc=(int)(log(double(c2-c1+1))/log(2.0));
    int t1=mx[r1][c1][kr][kc];
    int t2=mx[r2-(1<<kr)+1][c1][kr][kc];
    int t3=mx[r1][c2-(1<<kc)+1][kr][kc];
    int t4=mx[r2-(1<<kr)+1][c2-(1<<kc)+1][kr][kc];
    return max(max(t1,t2),max(t3,t4));
}
int main()
{
    while (~scanf("%d%d",&n,&m))
    {
        for (int i=1;i<=n;++i)
          for (int j=1;j<=m;++j)
            scanf("%d",&v[i][j]);
        init();
        int q;
        scanf("%d",&q);
        while (q--)
        {
            int r1,c1,r2,c2;
            scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
            int ans=query(r1,c1,r2,c2);
            printf("%d ",ans);
            if (v[r1][c1]==ans||v[r1][c2]==ans||v[r2][c1]==ans||v[r2][c2]==ans)
            printf("yes\n");
            else printf("no\n");
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值