D e s c r i p t i o n Description Description
给定一个 n × m n\times m n×m的01矩阵,有 T T T组询问
每次询问 ( x 1 , y 1 ) (x1,y1) (x1,y1)至 ( x 2 , y 2 ) (x2,y2) (x2,y2)中的最大正方形
数据范围: n , m ≤ 1 0 3 , T ≤ 1 0 6 n,m\leq 10^3,T\leq 10^6 n,m≤103,T≤106
S o l u t i o n Solution Solution
看到最大正方形就应该想起来这道题
列同样的方程求一遍,这里再列一遍,设 f [ i ] [ j ] f[i][j] f[i][j]表示以 ( i , j ) (i,j) (i,j)为右下角的最大正方形,显然当 ( i , j ) (i,j) (i,j)的值是1时
f [ i ] [ j ] = m i n { f [ i − 1 ] [ j ] , f [ i ] [ j − 1 ] , f [ i − 1 ] [ j − 1 ] } + 1 f[i][j]=min\{f[i-1][j],f[i][j-1],f[i-1][j-1]\}+1 f[i][j]=min{f[i−1][j],f[i][j−1],f[i−1][j−1]}+1
首先二分答案转判定,问题转换成为一个二维区间的最大值
考虑到没有修改,二维RMQ解决即可
设 g [ i ] [ j ] [ k ] [ l ] g[i][j][k][l] g[i][j][k][l]表示 ( k − 2 i − 1 , l − 2 j − 1 ) (k-2^i-1,l-2^j-1) (k−2i−1,l−2j−1)到 ( k , l ) (k,l) (k,l)的最大值
时间复杂度: O ( n 2 l o g n + T l o g n ) O(n^2logn+Tlogn) O(n2logn+Tlogn)【这里假设 m = n m=n m=n】
T i p s : Tips: Tips:
- RMQ数组要把次方项放前面,这样预处理更快
- g [ 0 ] [ 0 ] [ i ] [ j ] = f [ i ] [ j ] g[0][0][i][j]=f[i][j] g[0][0][i][j]=f[i][j]
- 对于 j = = 0 j==0 j==0的情况,需要将上一次的情况转移过来
- 最后,记得开编译开关
C o d e Code Code
#pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
#include<cctype>
#include<cstdio>
#include<algorithm>
#define LL long long
#define N 1025
using namespace std;int n,m,q,Log[N]={0,0,1},f[N][N],g[11][11][N][N],x1,y1,x2,y2,ans;
const int pw[11]={1,2,4,8,16,32,64,128,256,512,1024};
bool a[N][N];
inline LL read()
{
char c;LL d=1,f=0;
while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline int maxn(int x1,int y1,int x2,int y2)
{
int lx=Log[x2-x1+1],ly=Log[y2-y1+1];
int A=max(g[lx][ly][x2][y2],g[lx][ly][x1+pw[lx]-1][y1+pw[ly]-1]);
int B=max(g[lx][ly][x2][y1+pw[ly]-1],g[lx][ly][x1+pw[lx]-1][y2]);
return max(A,B);
}
signed main()
{
freopen("square.in","r",stdin);
freopen("square.out","w",stdout);
n=read();m=read();
for(register int i=3;i<N;i++) Log[i]=Log[i>>1]+1;
for(register int i=1;i<=n;i++)
for(register int j=1;j<=m;j++)
{
a[i][j]=read();
if(a[i][j]) f[i][j]=min(f[i-1][j-1],min(f[i][j-1],f[i-1][j]))+1;
g[0][0][i][j]=f[i][j];
}
for(register int i=0;i<=Log[n];i++)
for(register int j=0;j<=Log[m];j++)
{
if(i+j==0) continue;
for(register int k=pw[i];k<=n;k++)
for(register int l=pw[j];l<=m;l++)
{
if(j==0) g[i][j][k][l]=max(g[i-1][j][k][l],g[i-1][j][k-pw[i-1]][l]);else
g[i][j][k][l]=max(g[i][j-1][k][l],g[i][j-1][k][l-pw[j-1]]);
}
}
q=read();
while(q--)
{
x1=read();y1=read();x2=read();y2=read();
int l=1,r=min(y2-y1+1,x2-x1+1),mid=0;ans=0;
while(l<=r)
{
mid=l+r>>1;
if(maxn(x1+mid-1,y1+mid-1,x2,y2)>=mid) l=(ans=mid)+1;else r=mid-1;
}
printf("%d\n",ans);
}
}