P7153 [USACO20DEC] Square Pasture G 题解
对于每种集合只考虑包含这些点的最小的正方形,这样就不会多算。对于一个正方形,如果两条邻边上都没有奶牛,那就可以将边长减一。
考虑左边和上面的两条边。
$1.$ 如果两边上都有奶牛:
可以枚举左上角的点,然后对每个能覆盖到的点求出覆盖这个点最短的正方形的边长,最后对这些边长去个重,统计一下有多少个合法即可,时间复杂度 $O(n^3\log n)$。
$2.$ 如果两边上只有一边有奶牛:
下面假设是左侧边上没有奶牛,上边没有奶牛的情况类似处理。
那么底边一定也有奶牛,枚举这两条边的纵坐标,那么正方形的边长就知道了。考虑一个左侧边上没有奶牛的正方形,如果向右移一格覆盖到的奶牛集合不变,那这个正方形就不对答案有贡献。
于是可以枚举右侧边的横坐标,其横坐标加一一定是一个点的横坐标,时间复杂度 $O(n^3\log n)$。
参考代码:
#include<bits/stdc++.h>
#define ll long long
#define mxn 200003
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rept(i,a,b) for(int i=a;i<b;++i)
using namespace std;
struct node{
int x,y;
}a[203];
int n,t,ans,d[203],d1[203],d2[203],p1[203],p2[203];
set<int>s;
map<int,bool>mp;
signed main(){
scanf("%d",&n);
rep(i,1,n)scanf("%d%d",&a[i].x,&a[i].y),d1[i]=a[i].x,d2[i]=a[i].y;
sort(d1+1,d1+n+1);
sort(d2+1,d2+n+1);
rep(i,1,n){
p1[lower_bound(d1+1,d1+n+1,a[i].x)-d1]=i;
p2[lower_bound(d2+1,d2+n+1,a[i].y)-d2]=i;
}
rep(i,1,n){
rep(j,1,n)if(a[p1[i]].y>=d2[j]&&a[p2[j]].x>=d1[i]){
s.clear();
rep(k,1,n)if(a[k].x>=d1[i]&&a[k].y>=d2[j])s.insert(max(a[k].x-d1[i],a[k].y-d2[j]));
for(int k:s)if(k>=max(a[p1[i]].y-d2[j],a[p2[j]].x-d1[i]))ans++;
}
}
d[0]=-2e9;
rept(i,1,n){
rep(j,i+1,n){
int y1=a[p1[i]].y,y2=a[p1[j]].y,ds=d1[j]-d1[i];
if(y1>y2)swap(y1,y2);
if(y2-y1>ds)continue;
t=0;
mp.clear();
rep(k,1,n)if(a[p2[k]].x>=d1[i]&&a[p2[k]].x<=d1[j])d[++t]=d2[k],mp[d2[k]]=1;
int e2=lower_bound(d+1,d+t+1,y2)-d;
rep(k,e2+1,t){
if(d[k]-1-ds>=y1)break;
if(mp.find(d[k]-1-ds)==mp.end())ans++;
}
}
}
rept(i,1,n){
rep(j,i+1,n){
int y1=a[p2[i]].x,y2=a[p2[j]].x,ds=d2[j]-d2[i];
if(y1>y2)swap(y1,y2);
if(y2-y1>ds)continue;
t=0;
mp.clear();
rep(k,1,n)if(a[p1[k]].y>=d2[i]&&a[p1[k]].y<=d2[j])d[++t]=d1[k],mp[d1[k]]=1;
int e2=lower_bound(d+1,d+t+1,y2)-d;
rep(k,e2+1,t){
if(d[k]-1-ds>=y1)break;
if(mp.find(d[k]-1-ds)==mp.end())ans++;
}
}
}
cout<<ans+1;
return 0;
}