POJ3179 Corral the Cows

题意

Farmer John wishes to build a corral for his cows. Being finicky beasts, they demand that the corral be square and that the corral contain at least C (1 <= C <= 500) clover fields for afternoon treats. The corral's edges must be parallel to the X,Y axes.

FJ's land contains a total of N (C <= N <= 500) clover fields, each a block of size 1 x 1 and located at with its lower left corner at integer X and Y coordinates each in the range 1..10,000. Sometimes more than one clover field grows at the same location; such a field would have its location appear twice (or more) in the input. A corral surrounds a clover field if the field is entirely located inside the corral's borders.

Help FJ by telling him the side length of the smallest square containing C clover fields.

分析

参照evenbao的题解。

首先,我们发现答案是具有单调性的,也就是说,如果边长为C的正方形可以,那么比边长C大的正方形也可以,因此,可以二分答案

那么,我们怎么检验呢?

每个点的坐标最大时达到10000,因此,直接二维前缀和显然是会超时的

考虑将坐标离散化,然后求二维前缀和,由于N<=500,所以离散化后最多也只有1000个点

检验时,我们枚举正方形的左上角,用二分求出它的右下角,然后,判断正方形内是否有大于C的草量

时间复杂度\(O(N^2 \log N)\)

代码

#include<iostream>
#include<algorithm>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
	rg T data=0,w=1;
	rg char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-') w=-1;
		ch=getchar();
	}
	while(isdigit(ch))
		data=data*10+ch-'0',ch=getchar();
	return data*w;
}
template<class T>il T read(rg T&x){
	return x=read<T>();
}
typedef long long ll;
using namespace std;

struct data{
	int x,y;
}a[501];
int c,n,tot;
int rec[1002][1002],b[1002];
void discrete(){
	sort(b+1,b+tot+1);
	tot=unique(b+1,b+tot+1)-b-1;
	for(int i=1;i<=n;++i)
		++rec[lower_bound(b+1,b+tot+1,a[i].x)-b][lower_bound(b+1,b+tot+1,a[i].y)-b];
	b[++tot]=10001;
	for(int i=1;i<=tot;++i)
		for(int j=1;j<=tot;++j)
			rec[i][j]+=rec[i-1][j]+rec[i][j-1]-rec[i-1][j-1];
}
bool valid(int cur){
	if(cur>=b[tot]) return 1;
	int p=upper_bound(b+1,b+tot+1,b[tot]-cur+1)-b-1;
	for(int i=1;i<=p;++i)
		for(int j=1;j<=p;++j){
			int tx=upper_bound(b+1,b+tot+1,b[i]+cur-1)-b-1,
				ty=upper_bound(b+1,b+tot+1,b[j]+cur-1)-b-1;
			if(rec[tx][ty]-rec[i-1][ty]-rec[tx][j-1]+rec[i-1][j-1]>=c) return 1;
		}
	return 0;
}
int main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	read(c),read(n);
	for(int i=1;i<=n;++i)
		b[++tot]=read(a[i].x),b[++tot]=read(a[i].y);
	discrete();
	int l=1,r=10000;
	while(l<r){
		int mid=(l+r)>>1;
		if(valid(mid)) r=mid;
		else l=mid+1;
	}
	printf("%d\n",l);
	return 0;
}

再分析

lydrainbowcat有一份类似滑动窗口的代码,每次找覆盖C的最短区间,时间复杂度\(O(N^2)\)

左闭右开区间,前缀和base 1,这波操作简直天秀。

再代码

#include<iostream>
#include<algorithm>
#include<vector>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
	rg T data=0,w=1;
	rg char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-') w=-1;
		ch=getchar();
	}
	while(isdigit(ch))
		data=data*10+ch-'0',ch=getchar();
	return data*w;
}
template<class T>il T read(rg T&x){
	return x=read<T>();
}
typedef long long ll;
using namespace std;

vector<int> X,Y;
co int maxn=501,INF=0x7fffffff;
int sum[maxn][maxn];
vector<pair<int,int> > p;
int main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	int C=read<int>(),n=read<int>(),x,y;
	for(int i=1;i<=n;++i){
		int a=read<int>(),b=read<int>();
		p.push_back(make_pair(a,b));
		X.push_back(a);
		Y.push_back(b);
	}
	sort(p.begin(),p.end());
	sort(X.begin(),X.end());
	X.erase(unique(X.begin(),X.end()),X.end());
	sort(Y.begin(),Y.end());
	Y.erase(unique(Y.begin(),Y.end()),Y.end());
	x=X.size(),y=Y.size();
	X.push_back(INF),Y.push_back(INF);
	int pos=0;
	for(int i=1;i<=x;++i) // base 1
		for(int j=1;j<=y;++j){
			sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
			while(pos<n&&p[pos].first==X[i-1]&&p[pos].second==Y[j-1])
				++sum[i][j],++pos;
		}
	int ans=INF;
	for(int i=0;i<x;++i){ // [i,i1) & [j,j1)
		int i1=i+1,s=0,j=0,j1=1;
		int val=sum[i1][j1]-sum[i][j1]-sum[i1][j]+sum[i][j];
		while(1){
			while(val<C&&(i1<x||j1<y)){
				s=min(X[i1]-X[i],Y[j1]-Y[j]);
				while(X[i1]-X[i]<=s) ++i1;
				while(Y[j1]-Y[j]<=s) ++j1;
				val=sum[i1][j1]-sum[i][j1]-sum[i1][j]+sum[i][j];
			}
			if(val<C) break;
			ans=min(ans,s+1);
			++j;
			if(j==y) break;
			if(j1<=j) j1=j+1,s=0;
			else s-=Y[j]-Y[j-1];
			while(X[i1-1]-X[i]>s) --i1;
			val=sum[i1][j1]-sum[i][j1]-sum[i1][j]+sum[i][j];
		}
	}
	printf("%d\n",ans);
	return 0;
}

posted on 2019-02-17 20:56  autoint  阅读(166)  评论(0编辑  收藏  举报

导航