{题解}[jzoj4817]【NOIP2016提高A组五校联考4】square

传送

Description

Description

Analysis

显然的,可以 O(nm) 求出所有以(i,j)为右下角的 最大的 正方形的 边长
DP方程类似于Usaco5.3.4 Big Barn

求出所有F后,由于正方形可能超出询问中的边界
考虑二分答案Mid

因为,有些以 [i,j] 为右下角的正方形超出了范围,故二分Mid限制之

之后,问题转化为 记Mx为 左上角为(x1+mid-1,y1+mid-1) 右下角为(x2,y2)的矩阵中,F的最大值
于是,显然的,若 Mx>=Mid 说明Mx可行 二分上调,反之不行。

如图[图来自 ]
图

注意常数优化

2016.10.12 晚 更新

Code

#include <cmath>
#include <cstdio>
#include <cstring> 
#include <algorithm>
using namespace std;
const int N = 1010;
int n,m,Twi[11],f[N][N],RMQ[11][11][N][N];
bool map[N][N];
char ch;
int read()
{
    int t=0,p=1;
    for(ch=getchar();ch<'0' || ch>'9';ch=getchar())
        if(ch=='-') p=-1;
    for(;'0'<=ch && ch<='9';ch=getchar()) t=t*10+ch-'0';
    return t*p;
}
int query(int x1,int y1,int x2,int y2)
{
    if(x1 > x2 || y1 > y2) return 0;
    int l1 = log2(x2 - x1 + 1), l2 = log2(y2 - y1 + 1);
    int Rt = max(RMQ[l1][l2][x2][y2], RMQ[l1][l2][x2][y1 + Twi[l2] - 1]);
    Rt = max(Rt,max(RMQ[l1][l2][x1 + Twi[l1] - 1][y2],RMQ[l1][l2][x1 + Twi[l1] - 1][y1 + Twi[l2] - 1]));
    return Rt;
}
int main()
{
    freopen("D:/LiuYuanHao/4817.in","r",stdin);
    //freopen("square.in","r",stdin);freopen("square.out","w",stdout);
    Twi[0] = 1;
    for (int i = 1;i <= 10;i ++) Twi[i] = Twi[i - 1] << 1;
    n = read(),m = read();
    for (int i = 1;i <= n;i ++)
    {
        for (int j = 1;j <= m;j ++)
        {
            map[i][j]=read();
            if(map[i][j]) f[i][j]=min(min(f[i-1][j],f[i][j-1]),f[i-1][j-1])+1;
            RMQ[0][0][i][j]=f[i][j];
        }
    }
    for (int k = 1;k <= log2(n);k ++)
    {
        for (int i = 1;i <= n;i ++)
        {
            for (int j = 1;j <= m;j ++)
            {
                RMQ[0][k][i][j]=max(RMQ[0][k-1][i][j],RMQ[0][k-1][i][j-Twi[k-1]]);
                RMQ[k][0][i][j]=max(RMQ[k-1][0][i][j],RMQ[k-1][0][i-Twi[k-1]][j]);
            }
        }
    }
    for (int k = 1;k <= log2(n);k ++)
        for (int l = 1;l <= log2(m);l ++)
            for (int i = Twi[k];i <= n;i ++)
                for (int j = Twi[l];j <= m;j ++)
                    RMQ[k][l][i][j]=max(RMQ[k][l-1][i][j],RMQ[k][l-1][i][j-Twi[l-1]]);
    for (int _ = read();_ --;)
    {
       int x1,y1,x2,y2;
        x1 = read(),y1 = read(),x2 = read(),y2 = read();
        int l = 0,r = min(y2 - y1 + 1,x2 - x1 + 1);
        while (l + 1 < r)
        {
            int mid = (l + r) >> 1;
            if (query(x1 + mid - 1, y1 + mid - 1, x2, y2) >= mid) 
                 l = mid;
            else r = mid - 1;
        }
        while (query(x1 + l, y1 + l, x2, y2) > l) l ++;
        printf("%d\n",l);
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值