赶牛入圈

# 题目
建立畜栏,畜栏的形状必须是正方形,
有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 }

 

猜你喜欢

转载自www.cnblogs.com/hhyx/p/12431290.html
今日推荐