2

赶牛入圈

思路

这道题问最小边长,直接做比较难做,这时应该想到二分。在此之前我们先证明这个正方形至少有 \(3\) 条边上有点。如果只有两条边,一定能通过平移使得其满足。但是这题有一个很棘手的地方,点的范围是 \([1,10000]\),但是用到的点只有 \(500\) 个,坐标最多就 \(1000\) 个,所以应该考虑离散化,而且这里的离散化还需要注意绝对和相对的区别,原来两个数差很多,可能被映射成差 \(1\),为了避免诸如此类的情况,可以考虑用一种类似于双指针的思想,先枚举矩阵的右下角(上文的引理),然后找到第一个不在二分的 \(mid\) 范围内的最上方的点(注意方形与点不同,需要多 \(1\) 的坐标才能圈住),由于枚举右下角时是单调的,所以那个点也是单调的,可以在与枚举右下角相同的复杂度算出,然后用预处理的前缀和 \(O(1)\)。最坏会有 \(1000\) 个坐标,复杂度是 \(O(1000^2\log 10000)\),当然如果将横纵坐标分别离散化,可以优化成 \(O(500^2\log 10000)\)。还有一点,这题其实并不需要在乎是左上角、右上角、左下角、右下角,因为可以看作整体平移。

#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int c,n,a[N],cnt,sum[N][N],X[N],Y[N];
int find(int x){
	int l=0,r=cnt;
	while(l<r){
		int mid=l+r>>1;
		if(a[mid]>=x)r=mid;
		else l=mid+1;
	}
	return r;
}
bool check(int len){
	for(int x1=0,x2=1;x2<=cnt;++x2){
		while(a[x2]-a[x1+1]+1>len)++x1;
		for(int y1=0,y2=1;y2<=cnt;++y2){
			while(a[y2]-a[y1+1]+1>len)++y1;
			if(sum[x2][y2]-sum[x1][y2]-sum[x2][y1]+sum[x1][y1]>=c)return 1;
		}
	}
	return 0;
}
int main(){
	scanf("%d%d",&c,&n);
	for(int i=1;i<=n;++i){
		int x,y;
		scanf("%d%d",&x,&y);
		a[++cnt]=x,a[++cnt]=y;
		X[i]=x,Y[i]=y;
	}
	sort(a+1,a+1+cnt);
	cnt=unique(a+1,a+1+cnt)-a-1;
	for(int i=1;i<=n;++i){
		int xx=find(X[i]),yy=find(Y[i]);
		++sum[xx][yy];
	}
	for(int i=1;i<=cnt;++i)
		for(int j=1;j<=cnt;++j)sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
	int l=1,r=10000;
	while(l<r){
		int mid=l+r>>1;
		if(check(mid))r=mid;
		else l=mid+1;
	}
	printf("%d",r);
    return 0;
}

自己想的思路前面和上面大体一致,枚举左上角,但是直接用二分确定右下角,多一只 \(\log\)

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1010;
int c,n,a[N],sum[N][N],nn;
struct point{
	int x,y;
}p[N];
int find(int x){
    int l=0,r=n;
    while(l<r){
        int mid=l+r+1>>1;
        if(a[mid]<=x)l=mid;
        else r=mid-1;
    }
    return r;
}
bool check(int mid){
	int res=0;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j){
			int maxx=find(a[i]+mid-1),maxy=find(a[j]+mid-1);
			res=max(sum[maxx][maxy]-sum[maxx][j-1]-sum[i-1][maxy]+sum[i-1][j-1],res);
		}
	return res>=c;
}
int main(){
	scanf("%d%d",&c,&n);
	nn=n;
	int minx=1e9,miny=1e9,maxx=0,maxy=0;
	for(int i=1;i<=n;++i){
		int x,y;
		scanf("%d%d",&x,&y);
		p[i]={x,y};
		a[(i<<1)-1]=x,a[i<<1]=y;
		minx=min(minx,x),miny=min(miny,y),maxx=max(maxx,x),maxy=max(maxy,y);
	}
	sort(a+1,a+(n<<1|1));
	n=unique(a+1,a+(n<<1|1))-a-1;
	for(int i=1;i<=nn;++i){
		int x=lower_bound(a+1,a+1+n,p[i].x)-a,y=lower_bound(a+1,a+1+n,p[i].y)-a;
		++sum[x][y];
	}
	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]-sum[i-1][j-1];
	int l=0,r=max(maxx-minx+1,maxy-miny+1);
	while(l<r){
		int mid=l+r>>1;
		if(check(mid))r=mid;
		else l=mid+1;
	}
	printf("%d",r);
    return 0;
}
posted @ 2023-02-22 21:31  wscqwq  阅读(12)  评论(0编辑  收藏  举报