您的位置:首页 > 其它

JZOJ4817. square

2016-10-11 17:15 232 查看

题目大意

给定一个n×m的矩阵,其中有一些位置是障碍物。

现在有T个询问,每个询问查询一个子矩阵中最大的无障碍正方形边长是多少。

Data Constraint

n,m≤1000,T≤1000000

题解

设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解决。

注意状态的表达可以优化寻址时间。

时间复杂度:O(T logn)

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

,  Tab
;
int f

, g[MAXN][MAXN]

;
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 ;
}


以上.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: