1. 程式人生 > >Usaco Training Section 5.3 Big Barn

Usaco Training Section 5.3 Big Barn

在一個n*n的方格中找出最大的不包含障礙的正方形。(n<=1000,障礙數<=10000)

看起來好像有點難,不能隨便列舉。但仔細一想,可以發現:最大的正方形中至少有一個的一邊靠著障礙。於是我們只需列舉每個障礙上下左右最大的正方形是多少。

至於某一個方向最大的正方形怎麼求,我們以右邊的為例。我們先預處理每一列所有障礙的橫座標,排序。對於當前障礙在x行y列,j從y+1列向右推,每次用y列中最接近x的橫座標更新l,r,用l和r更新maxl和minr,正方形的邊長為min(minr-maxl,j-b[i].y)。一個優化:當minr-maxl<j-b[i].y時可推出,因為再往右推的結果<=當前的minr-maxl。

注意:多餘陣列不要亂開,usaco training給的空間只有16MB

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define inf 2147483647
#define mp make_pair
#define pii pair<int,int>
#define pb push_back
using namespace std;

inline int read(){
	int x=0;char c=getchar();
	while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x;
}

struct node{
	int x,y;
}b[10001];
int a[1001][1001];
vector<int> x[1001],y[1001];

inline bool cmp(node c,node d){
	return c.x<d.x;
}
inline bool cmp2(node c,node d){
	return c.y<d.y;
}

int main()
{
	freopen("bigbrn.in","r",stdin);
	freopen("bigbrn.out","w",stdout);
	int n=read(),m=read();
	for(int i=1;i<=m;++i) b[i].x=read(),b[i].y=read(),a[b[i].x][b[i].y]=1;
	sort(b+1,b+m+1,cmp);
	for(int i=1;i<=m;++i) x[b[i].y].pb(b[i].x);
	sort(b+1,b+m+1,cmp2);
	for(int i=1;i<=m;++i) y[b[i].x].pb(b[i].y);
	int ans=0;
	for(int i=1;i<=m;++i){
		int j=b[i].y+1,ml,mr;
		ml=0,mr=n+1;
		while(1){
			if(j>n) break;
			int pos,sz=x[j].size(),l,r;
			if(sz==0) l=1,r=n;
			else{
				pos=lower_bound(x[j].begin(),x[j].end(),b[i].x)-x[j].begin();
				if(pos==0) l=1,r=x[j][0]-1;
				else if(pos==sz) l=x[j][pos-1]+1,r=n;
				else l=x[j][pos-1]+1,r=x[j][pos]-1;
			}
			ml=max(ml,l);mr=min(mr,r);
			ans=max(ans,min(mr-ml+1,j-b[i].y));
			if(mr-ml+1<j-b[i].y) break;
			++j;
		}
		j=b[i].y-1;ml=0,mr=n+1;
		while(1){
			if(j<1) break;
			int pos,sz=x[j].size(),l,r;
			if(sz==0) l=1,r=n;
			else{
				pos=lower_bound(x[j].begin(),x[j].end(),b[i].x)-x[j].begin();
				if(pos==0) l=1,r=x[j][0]-1;
				else if(pos==sz) l=x[j][pos-1]+1,r=n;
				else l=x[j][pos-1]+1,r=x[j][pos]-1;
			}
			ml=max(ml,l);mr=min(mr,r);
			ans=max(ans,min(mr-ml+1,b[i].y-j));
			if(mr-ml+1<b[i].y-j) break;
			--j;
		}
		j=b[i].x+1;ml=0,mr=n+1;
		while(1){
			if(j>n) break;
			int pos,sz=y[j].size(),l,r;
			if(sz==0) l=1,r=n;
			else{
				pos=lower_bound(y[j].begin(),y[j].end(),b[i].y)-y[j].begin();
				if(pos==0) l=1,r=y[j][0]-1;
				else if(pos==sz) l=y[j][pos-1]+1,r=n;
				else l=y[j][pos-1]+1,r=y[j][pos]-1;
			}
			ml=max(ml,l);mr=min(mr,r);
			ans=max(ans,min(mr-ml+1,j-b[i].x));
			if(mr-ml+1<j-b[i].x) break;
			++j;
		}
		j=b[i].x-1;ml=0,mr=n+1;
		while(1){
			if(j<1) break;
			int pos,sz=y[j].size(),l,r;
			if(sz==0) l=1,r=n;
			else{
				pos=lower_bound(y[j].begin(),y[j].end(),b[i].y)-y[j].begin();
				if(pos==0) l=1,r=y[j][0]-1;
				else if(pos==sz) l=y[j][pos-1]+1,r=n;
				else l=y[j][pos-1]+1,r=y[j][pos]-1;
			}
			ml=max(ml,l);mr=min(mr,r);
			ans=max(ans,min(mr-ml+1,b[i].x-j));
			if(mr-ml+1<b[i].x-j) break;
			--j;
		}
	}
	printf("%d\n",ans);
	return 0; 
}