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

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,m103,T106


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[i1][j],f[i][j1],f[i1][j1]}+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) (k2i1,l2j1) ( 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:

  1. RMQ数组要把次方项放前面,这样预处理更快
  2. g [ 0 ] [ 0 ] [ i ] [ j ] = f [ i ] [ j ] g[0][0][i][j]=f[i][j] g[0][0][i][j]=f[i][j]
  3. 对于 j = = 0 j==0 j==0的情况,需要将上一次的情况转移过来
  4. 最后,记得开编译开关

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);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值