题目链接: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
",solve());
return 0;
}