最大子矩形问题
1.最大子矩形问题
2.莫队悬线法
定义
悬线:上端点为矩形上边界或障碍点且线上无障碍点的竖直线段。
平移:指一条悬线在不经过障碍点的情况下,左右移动
推论
推论1
在一个
推论2
最大子矩形一定是由一条悬线通过左右平移得来的。
(实际上每个子矩形都是可以通过平移一条悬线得来的)
算法
根据推论,如果我们可以
那么考虑如何
考虑预处理。
在预处理的过程中统计以
考虑如何处递推处理。
对于点
-
表示以 为下端点的悬线长度, -
表示以 为下端点的悬线可平移达到的最小左端点, -
表示以 为下端点的悬线可平移达到的最大右端点,
显然,如果点
-
, -
, -
,
对于
在预处理后,遍历矩形(即每一条悬线),求出最大值即为所求。
时间复杂度
实现
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read();
const int N = 1e3+5;
char a[N][N];//存储大矩形
int h[N][N],l[N][N],r[N][N]; //每个点的 h,l,r
ll ans;
namespace mxn
{
int max(long long x,int y){return x>y?x:y;}
int min(int x,int y){return x>y?y:x;}
}
int main(){
int n=read(),m=read();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
h[i][j]=1,r[i][j]=l[i][j]=j;//输入及初始化
}
for(int j=2;j<=m;j++) l[i][j]=(a[i][j-1]=='F'&&a[i][j]=='F')?l[i][j-1]:l[i][j];//初始化l数组
for(int j=m-1;j>0;j--) r[i][j]=(a[i][j+1]=='F'&&a[i][j]=='F')?r[i][j+1]:r[i][j];//初始化r数组
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
h[i][j]=(i>1&&a[i-1][j]=='F'&&a[i][j]=='F')?h[i-1][j]+1:h[i][j];// 'F'表示非障碍格
l[i][j]=(i>1&&a[i-1][j]=='F'&&a[i][j]=='F')?mxn::max(l[i-1][j],l[i][j]):l[i][j];
r[i][j]=(i>1&&a[i-1][j]=='F'&&a[i][j]=='F')?mxn::min(r[i-1][j],r[i][j]):r[i][j];
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(i>1&&a[i][j]=='F')
ans=mxn::max((r[i][j]-l[i][j]+1)*h[i][j],ans);//遍历每个非障碍点寻找最大值即为所求
printf("%lld",ans);
return 0;
}
inline int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-') f=0;
c=getchar();
}
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48,c=getchar();
return f?x:(~(x-1));
}
例题
本文作者:yzjznbQwQ
本文链接:https://www.cnblogs.com/yzjznbQwQ/articles/18648124
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步