BZOJ1720:[Usaco2006 Jan]Corral the Cows 奶牛围栏

我对二分的理解:https://www.cnblogs.com/AKMer/p/9737477.html

题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1720

坐标值域很大,但是真正涉及的只有\(500\)个,我们可以离散化做。二分长度,直接二维前缀和检查就行了

h时间复杂度:\(O(log10000*n^2*logn)\)

空间复杂度:\(O(n)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;

int n,c,cnt1,cnt2;
int x[505],y[505],sum[505][505];

int read() {
	int x=0,f=1;char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
	return x*f;
}

struct point {
	int x,y,x_id,y_id;
}p[505];

bool check(int len) {
	for(int i=1;i<=cnt1;i++)
		for(int j=1;j<=cnt2;j++) {
			int X=upper_bound(x+1,x+cnt1+1,x[i]-len)-x-1;
			int Y=upper_bound(y+1,y+cnt2+1,y[j]-len)-y-1;
			if(sum[i][j]-sum[i][Y]-sum[X][j]+sum[X][Y]>=c)//二维前缀和
				return 1;
		}
	return 0;
}

int main() {
	c=read(),n=read();
	for(int i=1;i<=n;i++) {
		p[i].x=x[i]=read();
		p[i].y=y[i]=read();
	}
	sort(x+1,x+n+1);sort(y+1,y+n+1);
	cnt1=unique(x+1,x+n+1)-x-1;
	cnt2=unique(y+1,y+n+1)-y-1;
	for(int i=1;i<=n;i++) {
		p[i].x_id=lower_bound(x+1,x+cnt1+1,p[i].x)-x;
		p[i].y_id=lower_bound(y+1,y+cnt2+1,p[i].y)-y;
	}
	for(int i=1;i<=n;i++)
		sum[p[i].x_id][p[i].y_id]++;
	for(int i=1;i<=cnt1;i++)
		for(int j=1;j<=cnt2;j++)
			sum[i][j]=sum[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];//离散化,前缀和预处理
	int l=0,r=10000;
	while(l<r) {
		int mid=(l+r)>>1;
		if(check(mid))r=mid;
		else l=mid+1;//二分,保证所有长度在[r,10000]的正方形可以圈出c块草
	}printf("%d\n",r);//最短的那个长度就是r
	return 0;
}
posted @ 2018-10-06 09:59  AKMer  阅读(172)  评论(0编辑  收藏  举报