AcWing 121 赶牛入圈 (二分+离散化)

题目链接:https://www.acwing.com/problem/content/description/123/

最朴素的做法是,暴力枚举每个正方形,维护前缀和判断是否符合条件,但是坐标范围太大
注意到只有 500 个点,所以可以将坐标离散化一下

正方形的边长显然满足二分性,所以二分边长即可

离散化之后,每次枚举时,需要二分找出边长大于 \(Mid\) 的点的位置,注意边界处理等小细节

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;

const int maxn = 510;

int C,N;
int x[maxn], y[maxn], xx[maxn], yy[maxn], sum[maxn][maxn], cntx, cnty;

bool Check(int Mid){
	for(int i=1;i<=cntx;++i){
		int lx = lower_bound(xx + 1, xx + 1 + cntx, xx[i] - Mid + 1) - xx;

		for(int j=1;j<=cnty;++j){
			int ly = lower_bound(yy + 1, yy + 1 + cnty, yy[j] - Mid + 1) - yy;

			int tmp = sum[i][j] - sum[i][ly-1] - sum[lx-1][j] + sum[lx-1][ly-1];
			if(tmp >= C){
				return true;
			}
		}
	}
	return false;
}

int solve(){
	int L = 1, R = 10000;
	
	while(L < R){
		int Mid = (L + R) >> 1;
		if(Check(Mid)){
			R = Mid;
		}else{
			L = Mid + 1;
		}
	}
	
	return L;
}

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

int main(){
	C = read(), N = read();
	for(int i=1;i<=N;++i){
		x[i] = read(), y[i] = read(); 
		xx[i] = x[i], yy[i] = y[i];
	}
	
	sort(xx + 1, xx + 1 + N);
	cntx = unique(xx + 1, xx + 1 + N) - xx - 1;
	
	sort(yy + 1, yy + 1 + N);
	cnty = unique(yy + 1, yy + 1 + N) - yy - 1;
	
	for(int i=1;i<=N;++i){
		x[i] = lower_bound(xx + 1, xx + 1 + cntx, x[i]) - xx;
		y[i] = lower_bound(yy + 1, yy + 1 + cnty, y[i]) - yy;
		++sum[x[i]][y[i]];
	}

	for(int i=1;i<=cntx;++i){
		for(int j=1;j<=cnty;++j){
			sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + sum[i][j];
		}
	}
	
	printf("%d\n",solve());
	
	return 0;
}
posted @ 2020-11-06 11:02  Tartarus_li  阅读(84)  评论(0编辑  收藏  举报