# 题目
建立畜栏,畜栏的形状必须是正方形,
有n个三叶草,为1*1的正方形,用左下角的坐标来代表,可能会有覆盖,至少包含c个三叶草的情况下求包含所有三叶草的最小畜栏
# 题解
1) 因为一定是正方形,二分正方形的边长
2) 性质:在最优解中,正方形的四条边中至少有两条对边是有点的,否则,就可以以一对邻边为基准缩小正方形
3) 二维前缀和统计正方形内的点的个数,最坏枚举1e4^2 ,大概是1e8,但是点的个数只有500个,离散化后再计算,离散化后再坐标区间内从小到大遍历并判断是否存在该点,保证了离散化后映射到的原始数据是从小到大排序的
4) Check 只需要枚举所有点,判断作为正方形的右上角是否合法,如果合法再利用前缀和判断点的个数是否满足要求
1 #include<bits/stdc++.h>
2 using namespace std;
3 const int MAX=1e4+10,N=5e2+10;
4 int hx[MAX],hy[MAX];//存的是离散化后的坐标
5 int n,c;
6 int x[N],y[N];//离散后保存的数组
7 int s[N][N];//离散化后的前缀和
8 int cntx,cnty;
9 struct node{
10 int x,y;
11 }a[N];
12 bool check(int edge){//二分的值是边长
13 for(int i=hx[edge];i<=cntx;i++)
14 for(int j=hy[edge];j<=cnty;j++){
15 int x0=0,y0=0;
16 if(x[i]-edge+1>=0) x0=hx[x[i]-edge];
17 if(y[j]-edge+1>=0) y0=hy[y[j]-edge];
18 if(s[i][j]-s[x0][j]-s[i][y0]+s[x0][y0]>=c)
19 return 1;
20 }
21 return 0;
22 }
23 int main(){
24 ios::sync_with_stdio(0);
25 cin.tie(0);
26 cout.tie(0);
27 cin>>c>>n;
28
29 for(int i=1;i<=n;i++){
30 cin>>a[i].x>>a[i].y;
31 hx[a[i].x]++;
32 hy[a[i].y]++;
33 }
34
35 for(int i=1;i<=10000;i++){//从前往后遍历可能覆盖的区间保证了从小到大的排序
36 if(hx[i])
37 x[++cntx]=i;
38 hx[i]=cntx;
39 if(hy[i])
40 y[++cnty]=i;
41 hy[i]=cnty;
42 }
43
44 for(int i=1;i<=n;i++)
45 s[hx[a[i].x]][hy[a[i].y]]++;
46
47 for(int i=1;i<=cntx;i++)
48 for(int j=1;j<=cnty;j++)
49 s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+s[i][j];
50
51 int l=1,r=10000;
52 while(l<r){
53 int mid=l+r>>1;
54 if(check(mid))
55 r=mid;
56 else
57 l=mid+1;
58 }
59 cout<<l<<endl;
60 return 0;
61 }