JZOJ 4817. 【NOIP2016提高A组五校联考4】square

Introduction

给你一个 NM 的矩阵,给你T组询问,每组询问给定一个子矩阵,求一个最大的正方形的边长,使这个正方形内的所有元素都为 1 且这个正方形在子矩阵内.
数据范围
N,M<=1000,T<=1000000

Solution

这道题很显然是DP。
Fi,j 表示以(i,j)为右下角,符合题意的最大边长。
那么转移方程为

Fi,j=max(Fi1,j,Fi,j1,Fi1,j1)Ai,j=1

可是这样远远不能AC.
这个时候我们想到了RMQ算法(二维的)。
我们设 rmqi,j,k,l 为当前以 (k2i+1,l2j+1) 为右下角, (k,l) 为右下角的正方形符合题意的最大边长。
rmqi,j,k,l 由之前的3个小矩阵更新。
所以转移方程为
rmqi,j,k,l=max(rmqi1,j,k2i,l,rmqi,j1,k,l2j,rmqi1,j1,k2i,l2j)

特殊情况:
①i=0,那么 rmqi,j,k,l=max(rmqi,j1,k,l2j)
②j=0,那么 rmqi,j,k,l=max(rmqi1,j,k2i,l)
询问
对于询问,我们只需要去求4个矩阵的最大值就好了^_^
m1=log2(x2x1+1)m2=log2(y2y1+1)
ans=max(rmq[m1][m2][x2][y2],rmq[m1][m2][x1+2m11][y1+2m21]),rmq[m1][m2][x2][y1+2m21],rmq[m1][m2][x1+2m11][y2]))

然后ans≥mid就合法,否则不合法。

Code

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define N 1003
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int _2[11],rmq[10][10][N][N];
int i,j,k,l,r,mid,q,n,m,temp,X1,Y1,X2,Y2,ans;
inline int read()
{
    int data=0;
    char ch=0;
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar();
    return data;
}
bool ok(int X1,int Y1,int X2,int Y2,int mid)
{
    int lx=log2(X2-X1+1),ly=log2(Y2-Y1+1);
    ans=max(max(rmq[lx][ly][X2][Y2],rmq[lx][ly][X1+_2[lx]-1][Y1+_2[ly]-1]),
            max(rmq[lx][ly][X2][Y1+_2[ly]-1],rmq[lx][ly][X1+_2[lx]-1][Y2]));
    if (ans>=mid) return 1;return 0;
}
int main()
{
    _2[0]=1;fo(i,1,10) _2[i]=_2[i-1]*2;
    n=read();m=read();
    fo(i,1,n)
        fo(j,1,m) rmq[0][0][i][j]=read();
    fo(i,2,n)
        fo(j,2,m)
            if (rmq[0][0][i][j])
                rmq[0][0][i][j]=min(min(rmq[0][0][i-1][j],rmq[0][0][i][j-1]),rmq[0][0][i-1][j-1])+1;
    fo(i,0,log2(n))
        fo(j,0,log2(m))
            if (!i && !j) continue;
            else fo(k,_2[i],n)
                     fo(l,_2[j],m)
                     {
                         if (!i) rmq[i][j][k][l]=max(rmq[i][j-1][k][l],rmq[i][j-1][k][l-_2[j-1]]);else
                         if (!j) rmq[i][j][k][l]=max(rmq[i-1][j][k][l],rmq[i-1][j][k-_2[i-1]][l]);else
                         rmq[i][j][k][l]=max(max(rmq[i-1][j][k][l],rmq[i-1][j][k-_2[i-1]][l]),
                                             max(rmq[i][j-1][k][l],rmq[i][j-1][k][l-_2[j-1]]));
                     }
    q=read();
    fo(i,1,q)
    {
        X1=read(),Y1=read(),X2=read(),Y2=read();
        l=0;r=min(X2-X1+1,Y2-Y1+1);
        while (l<r)
        {
            if (l==r-1)
            {
                if (ok(X1+r-1,Y1+r-1,X2,Y2,r)) l=r;
                break;
            }
            mid=(l+r)/2;
            if (ok(X1+mid-1,Y1+mid-1,X2,Y2,mid)) l=mid;else r=mid-1;
        }
        printf("%d\n",l);
    }
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值