题目大意
给定一个
n×m
的矩阵,其中有一些位置是障碍物。
现在有
T
个询问,每个询问查询一个子矩阵中最大的无障碍正方形边长是多少。
Data Constraint
题解
设
f[i][j]
表示以
(i,j)
为右下角,最大能取到的边长长度。
显然
f[i][j]=min(f[i−1][j],f[i][j−1],f[i−1][j−1])+1
然后对于每个询问,我们考虑二分答案。对于当前二分的答案,我们需要查询在一个二维区域内是否存在 f 的值大于等于当前答案。这个可以二维RMQ解决。
注意状态的表达可以优化寻址时间。
时间复杂度:
SRC
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std ;
#define N 1000 + 10
const int MAXN = 10 ;
int a[N][N], Tab[N] ;
int f[N][N] , g[MAXN][MAXN][N][N] ;
int n , m , Q ;
inline int Max( int x , int y ) { return x > y ? x : y ; }
inline int Min( int x , int y ) { return x < y ? x : y ; }
inline int Read() {
int ret = 0 ;
char ch = getchar() ;
while ( ch < '0' || ch > '9' ) ch = getchar() ;
while ( ch >= '0' && ch <= '9' ) ret = ret * 10 + ch - '0' , ch = getchar() ;
return ret ;
}
inline void Write( int x ) {
if ( x < 10 ) putchar( x + '0' ) ;
else {
Write( x / 10 ) ;
putchar( x % 10 + '0' ) ;
}
}
inline void Pre() {
for (int i = 1 ; i <= 1000 ; i ++ ) Tab[i] = log(i) / log(2) ;
for (int k = 0 ; k < MAXN ; k ++ ) {
for (int l = 0 ; l < MAXN ; l ++ ) {
if ( !k && !l ) continue ;
for (int i = 1 ; i <= n ; i ++ ) {
for (int j = 1 ; j <= m ; j ++ ) {
if ( k ) {
if ( g[k-1][l][i][j] > g[k][l][i][j] ) g[k][l][i][j] = g[k-1][l][i][j] ;
if ( i - (1 << (k - 1)) > 0 && g[k-1][l][i-(1<<(k-1))][j] > g[k][l][i][j] ) g[k][l][i][j] = g[k-1][l][i-(1<<(k-1))][j] ;
}
if ( l ) {
if ( g[k][l-1][i][j] > g[k][l][i][j] ) g[k][l][i][j] = g[k][l-1][i][j] ;
if ( j - (1 << (l - 1)) > 0 && g[k][l-1][i][j-(1<<(l-1))] > g[k][l][i][j] ) g[k][l][i][j] = g[k][l-1][i][j-(1<<(l-1))] ;
}
}
}
}
}
}
inline int Find( int x1 , int y1 , int x2 , int y2 ) {
int k1 = Tab[x2-x1+1] ;
int k2 = Tab[y2-y1+1] ;
int ret = g[k1][k2][x2][y2] ;
if ( g[k1][k2][x1+(1<<k1)-1][y1+(1<<k2)-1] > ret ) ret = g[k1][k2][x1+(1<<k1)-1][y1+(1<<k2)-1] ;
if ( g[k1][k2][x1+(1<<k1)-1][y2] > ret ) ret = g[k1][k2][x1+(1<<k1)-1][y2] ;
if ( g[k1][k2][x2][y1+(1<<k2)-1] > ret ) ret = g[k1][k2][x2][y1+(1<<k2)-1] ;
return ret ;
}
int main() {
freopen( "square.in" , "r" , stdin ) ;
freopen( "square.out" , "w" , stdout ) ;
n = Read() , m = Read() ;
for (int i = 1 ; i <= n ; i ++ ) {
for (int j = 1 ; j <= m ; j ++ ) {
a[i][j] = Read() ;
if ( !a[i][j] ) f[i][j] = 0 ;
else {
if ( f[i][j-1] < f[i-1][j] ) f[i][j] = f[i][j-1] ;
else f[i][j] = f[i-1][j] ;
if ( f[i-1][j-1] < f[i][j] ) f[i][j] = f[i-1][j-1] ;
f[i][j] ++ ;
}
g[0][0][i][j] = f[i][j] ;
}
}
Pre() ;
Q = Read() ;
for (int i = 1 ; i <= Q ; i ++ ) {
int x1 = Read() , y1 = Read() , x2 = Read() , y2 = Read() ;
int l = 0 , r = Min( y2 - y1 , x2 - x1 ) + 1 , ans = 0 ;
while ( l <= r ) {
int mid = (l + r) >> 1 ;
if ( Find( x1 + mid - 1 , y1 + mid - 1 , x2 , y2 ) >= mid ) l = mid + 1 , ans = mid ;
else r = mid - 1 ;
}
Write( ans ) ;
putchar( '\n' ) ;
}
return 0 ;
}
以上.