2018.09.29 bzoj3885: Cow Rectangles(悬线法+二分)

时间:2023-03-08 23:53:03
2018.09.29 bzoj3885: Cow Rectangles(悬线法+二分)

传送门

对于第一个问题,直接用悬线法求出最大的子矩阵面积,然后对于每一个能得到最大面积的矩阵,我们用二分法去掉四周的空白部分来更新第二个答案。

代码:

#include<bits/stdc++.h>
#define M 1005
using namespace std;
int n,x,y,a[M][M],b[M][M],L[M][M],R[M][M],h[M][M],sum[M][M],lpos[M][M],rpos[M][M],ans1=0,ans2=0;
char s[4];
inline int calc(int x1,int y1,int x2,int y2){return sum[x2][y2]+sum[x1-1][y1-1]-sum[x2][y1-1]-sum[x1-1][y2];}
inline int solve(int x1,int y1,int x2,int y2){
	int l=x1,r=x2,ans=l,tmp=calc(x1,y1,x2,y2);
	while(l<=r){
		int mid=l+r>>1;
		if(calc(mid,y1,x2,y2)==tmp)l=mid+1,ans=mid;
		else r=mid-1;
	}
	x1=ans,l=x1,r=x2;
	while(l<=r){
		int mid=l+r>>1;
		if(calc(x1,y1,mid,y2)==tmp)r=mid-1,ans=mid;
		else l=mid+1;
	}
	x2=ans,l=y1,r=y2,ans=y1;
	while(l<=r){
		int mid=l+r>>1;
		if(calc(x1,mid,x2,y2)==tmp)l=mid+1,ans=mid;
		else r=mid-1;
	}
	y1=ans,l=y1,r=y2,ans=y2;
	while(l<=r){
		int mid=l+r>>1;
		if(calc(x1,y1,x2,mid)==tmp)r=mid-1,ans=mid;
		else l=mid+1;
	}
	y2=ans;
	return (x2-x1)*(y2-y1);
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)scanf("%d%d%s",&x,&y,s),s[0]=='H'?a[x+1][y+1]=1:b[x+1][y+1]=1;
	n=1001;
	for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)sum[i][j]=sum[i-1][j]+sum[i][j-1]+a[i][j]-sum[i-1][j-1];
	for(int i=1;i<=n;++i){
		int ltmp=0,rtmp=n;
		for(int j=1;j<=n;++j){
			if(b[i][j])ltmp=j+1;
			else L[i][j]=ltmp;
		}
		for(int j=n;j;--j){
			if(b[i][j])rtmp=j-1;
			else R[i][j]=rtmp;
		}
		for(int j=1;j<=n;++j){
			if(b[i][j])continue;
			h[i][j]=h[i-1][j]+1;
			if(!(h[i][j]^1))lpos[i][j]=L[i][j],rpos[i][j]=R[i][j];
			else lpos[i][j]=max(L[i][j],lpos[i-1][j]),rpos[i][j]=min(R[i][j],rpos[i-1][j]);
			int tmp1=calc(i-h[i][j]+1,lpos[i][j],i,rpos[i][j]),tmp2=solve(i-h[i][j]+1,lpos[i][j],i,rpos[i][j]);
			if(tmp1>ans1)ans1=tmp1,ans2=tmp2;
			else if(tmp1==ans1)ans2=min(ans2,tmp2);
		}
	}
	printf("%d\n%d",ans1,ans2);
	return 0;
}