题目大意:
坐标系上给出n个点,分”H”和”G”,一个整点坐标上至多一个点。 现在求一个不包含”G”的包含尽量多”H”的子矩形,然后在保证”H”最多的情况下还要问最小面积。 输出”H”的最大数量,和保证”H”最多时的最小矩形面积,坐标范围在[0,1000]。
解题思路:
先用悬线法求出极大子矩阵,再二分边界,消去不含’H’的部分即可。
悬线法:对每个位置求出向上的没有障碍点的最大距离,再用单调栈求出左右能拓展的最远边界即是一个最大子矩阵,时间复杂度O(n2)O(n2),而且在一些题目中可以离散化.
#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int n,top,ans1,ans2,a[N][N],f[N][N],stk[N],l[N],r[N],h[N];
int get_num(int L,int R,int U,int D)
{
return f[D][R]-f[D][L-1]-f[U-1][R]+f[U-1][L-1];
}
int get_area(int L,int R,int U,int D)
{
int fl,fr,fu,ll,rr;
ll=L,rr=R;
while(ll<=rr)
{
int mid=ll+rr>>1;
if(!get_num(L,mid,U,D))ll=mid+1;
else rr=mid-1;
}fl=ll;
ll=L,rr=R;
while(ll<=rr)
{
int mid=ll+rr>>1;
if(!get_num(mid,R,U,D))rr=mid-1;
else ll=mid+1;
}fr=rr;
ll=U,rr=D;
while(ll<=rr)
{
int mid=ll+rr>>1;
if(!get_num(L,R,U,mid))ll=mid+1;
else rr=mid-1;
}fu=ll;
return (fr-fl)*(D-fu);
}
int main()
{
//freopen("lx.in","r",stdin);
scanf("%d",&n);int x,y;char s[5];
while(n--)scanf("%d%d%s",&x,&y,s),a[++x][++y]=(s[0]=='H'?1:2);
n=1001;
for(int i=1;i<=n;i++)
{
int tmp=0;
for(int j=1;j<=n;j++)
f[i][j]=f[i-1][j]+(a[i][j]==1?++tmp:tmp);
}
h[0]=h[n+1]=-1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)h[j]=(a[i][j]<2?h[j]+1:0);
top=0;
for(int j=1;j<=n+1;j++)
{
while(h[j]<h[stk[top]])r[stk[top--]]=j;
stk[++top]=j;
}
top=0;
for(int j=n;j>=0;j--)
{
while(h[j]<h[stk[top]])l[stk[top--]]=j;
stk[++top]=j;
}
for(int j=1;j<=n;j++)
if(h[j])
{
int tmp=get_num(l[j]+1,r[j]-1,i-h[j]+1,i);
if(tmp>ans1)ans1=tmp,ans2=get_area(l[j]+1,r[j]-1,i-h[j]+1,i);
else if(tmp==ans1)ans2=min(ans2,get_area(l[j]+1,r[j]-1,i-h[j]+1,i));
}
}
cout<<ans1<<'\n'<<ans2<<'\n';
return 0;
}