题目:
分析:
法一:二分套二分
如果是二分最大矩阵的长,再二分最大矩阵的宽,明显是错的:
1 1 1 0
0 1 1 0
像这样一组数据,如果宽二分到3,那么就不再会考虑宽为2的矩阵了,而最优矩阵是2*2=4
如果再先二分矩阵的宽,再二分矩阵的长,可以水掉更多的点,但还是没有正确性。
只有矩形的面积才是满足单调性的,如果一个面积大的矩形存在,面积小的也一定存在,二分完面积之后,再二分宽,然后枚举每一个点n^2 check
复杂度:O(n*m*logn*log(n*m))(有点悬)
法二:悬线法
对于一个点,我们想利用它来扩展出对于包括它的,最大的一个矩形。初始化三个值:l[i][j],r[i][j],up[i][j]
分别表示:某个点向左、向右、向上最多能扩展的位置。
为什么能保证矩阵合法?
l[i][j]=max(l[i-1][j],l[i][j]);
r[i][j]=min(r[i-1][j],r[i][j]);
up[i][j]=up[i-1][j]+1;
代码里面的这三句保证了矩阵一定是合法的。
为什么能保证每一个对答案有贡献的矩阵能够找齐?
001100
111111
如果对于第二行的3、4个点,它们找到的矩阵是2*2=4的,而1*6=6的矩阵可以由1、2、5、6找到。
#include<bits/stdc++.h> using namespace std; #define N 1005 #define ri register int int a[N][N],l[N][N],r[N][N],up[N][N],n,m; int read()//ll { int x=0,fl=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') fl=-1; ch=getchar(); } while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar(); return x*fl; } int main() { freopen("question.in","r",stdin); freopen("question.out","w",stdout); int fl=0,ans; n=read(), m=read(); for(ri i=1;i<=n;++i) for(ri j=1;j<=m;++j) a[i][j]=read(),l[i][j]=j,r[i][j]=j,up[i][j]=1,fl|=a[i][j]; for(ri i=1;i<=n;++i) for(ri j=2;j<=m;++j) if(a[i][j-1] && a[i][j]) l[i][j]=l[i][j-1]; for(ri i=1;i<=n;++i) for(ri j=m-1;j>=1;--j) if(a[i][j+1] && a[i][j]) r[i][j]=r[i][j+1]; for(ri i=1;i<=n;++i) for(ri j=1;j<=m;++j){ if(a[i][j] && a[i-1][j]){ l[i][j]=max(l[i-1][j],l[i][j]); r[i][j]=min(r[i-1][j],r[i][j]); up[i][j]=up[i-1][j]+1; } ans=max( ans,up[i][j]*(r[i][j]-l[i][j]+1) ); } printf("%d ",fl ? ans : 0); } /* 7 8 1 1 0 0 1 0 1 0 0 1 1 1 1 1 0 1 0 0 0 0 0 0 1 1 0 0 1 1 0 1 1 0 1 1 1 1 1 0 0 1 0 1 1 1 1 1 1 0 0 0 0 1 0 0 0 1 8 1 0 0 1 0 0 0 1 1 */