BZOJ传送门
洛谷传送门
解析:
考虑什么样的点可能组成矩形,边已经行不通了,限制不够。
矩形的对角线等长且共中点。
所以将所有 n 2 n^2 n2条对角线提出来自定义排个序就行了。
然后暴力枚举所有合法的对角线对,可以证明,这样没有多余的枚举且每个矩形都枚举了,复杂度为为 O ( 矩 形 个 数 ) = O ( n 2 n ) O(矩形个数)=O(n^2\sqrt n) O(矩形个数)=O(n2n),而且这样的数据极难构造,证明可以见:https://blog.youkuaiyun.com/wang3312362136/article/details/83003126
而且现在所有的题解都是这个做法,但是为什么旋转卡壳是错的呢?
考虑按照极角对所有共中点且等长的排序后,显然尽量垂直的答案会更大,这就是旋转卡壳的依据。
所以旋转卡壳的正确性哪里出了问题?
本博客最后有我的一份旋转卡壳的代码,但是我还是不知道哪里错了,如果有读者发现了错误,请与我联系,感激。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define cs const
inline int getint(){
re char c;
re bool f=0;
while(!isdigit(c=gc()))if(c=='-')f=1;re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return f?-num:num;
}
struct line{
int x_1,x_2,y_1,y_2;
inline ll len()cs{return (ll)(x_1-x_2)*(x_1-x_2)+(ll)(y_1-y_2)*(y_1-y_2);}
friend bool operator<(cs line &a,cs line &b){
if(a.x_1+a.x_2!=b.x_1+b.x_2)return a.x_1+a.x_2<b.x_1+b.x_2;
if(a.y_1+a.y_2!=b.y_1+b.y_2)return a.y_1+a.y_2<b.y_1+b.y_2;
return a.len()<b.len();
}
friend bool operator==(cs line &a,cs line &b){
return a.x_1+a.x_2==b.x_1+b.x_2&&a.y_1+a.y_2==b.y_1+b.y_2&&a.len()==b.len();
}
}l[1500*1500+5];
inline ll area(cs line &a,cs line &b){
assert(a==b);
re int x_1=b.x_1-a.x_1,y_1=b.y_1-a.y_1;
re int x_2=b.x_2-a.x_1,y_2=b.y_2-a.y_1;
return max((ll)x_1*y_2,(ll)y_1*x_2)-min((ll)x_1*y_2,(ll)y_1*x_2);
}
struct Point{int x,y;}p[1505];
int n,cnt;
ll ans;
signed main(){
n=getint();
for(int re i=1;i<=n;++i){
p[i].x=getint(),p[i].y=getint();
}
for(int re i=1;i<=n;++i){
for(int re j=1;j<i;++j){
++cnt;
l[cnt].x_1=p[i].x;
l[cnt].y_1=p[i].y;
l[cnt].x_2=p[j].x;
l[cnt].y_2=p[j].y;
}
}
sort(l+1,l+cnt+1);
for(int re i=1,j;i<=cnt;i=j+1){
for(j=i;j+1<=cnt&&l[i]==l[j+1];++j);
for(int re k=i;k<=j;++k){
for(int re t=i;t<k;++t)
ans=max(ans,area(l[k],l[t]));
}
}
cout<<ans<<"\n";
return 0;
}
代码(旋转卡壳):
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define cs const
inline int getint(){
re char c;
re bool f=0;
while(!isdigit(c=gc()))if(c=='-')f=1;re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return f?-num:num;
}
struct line{
int x_1,x_2,y_1,y_2;
inline ll len()cs{return (ll)(x_1-x_2)*(x_1-x_2)+(ll)(y_1-y_2)*(y_1-y_2);}
friend bool operator<(cs line &a,cs line &b){
if(a.x_1+a.x_2!=b.x_1+b.x_2)return a.x_1+a.x_2<b.x_1+b.x_2;
if(a.y_1+a.y_2!=b.y_1+b.y_2)return a.y_1+a.y_2<b.y_1+b.y_2;
if(a.len()!=b.len())return a.len()<b.len();
return a.x_1-a.x_2<b.x_1-b.x_1;
}
friend bool operator==(cs line &a,cs line &b){
return a.x_1+a.x_2==b.x_1+b.x_2&&a.y_1+a.y_2==b.y_1+b.y_2&&a.len()==b.len();
}
}l[1500*1500+5];
inline ll area(cs line &a,cs line &b){
assert(a==b);
re int x_1=b.x_1-a.x_1,y_1=b.y_1-a.y_1;
re int x_2=b.x_2-a.x_1,y_2=b.y_2-a.y_1;
return max((ll)x_1*y_2,(ll)y_1*x_2)-min((ll)x_1*y_2,(ll)y_1*x_2);
}
struct Point{int x,y;}p[1505];
int n,cnt;
ll ans;
signed main(){
n=getint();
for(int re i=1;i<=n;++i){
p[i].x=getint(),p[i].y=getint();
}
for(int re i=1;i<=n;++i){
for(int re j=1;j<i;++j){
++cnt;
l[cnt].x_1=p[i].x;
l[cnt].y_1=p[i].y;
l[cnt].x_2=p[j].x;
l[cnt].y_2=p[j].y;
if(l[cnt].y_1>l[cnt].y_2){
swap(l[cnt].y_1,l[cnt].y_2);
swap(l[cnt].x_1,l[cnt].x_2);
}
else if(l[cnt].y_1==l[cnt].y_2){
if(l[cnt].x_1<l[cnt].x_2)swap(l[cnt].x_1,l[cnt].x_2);
}
}
}
sort(l+1,l+cnt+1);
for(int re i=1,j;i<=cnt;i=j+1){
for(j=i;j+1<=cnt&&l[i]==l[j+1];++j);
int t=i;
for(int re k=i;k<=j;++k){
while(t+1<=j&&area(l[k],l[t])<=area(l[k],l[t+1]))++t;
ans=max(ans,area(l[k],l[t]));
if(t+1<=j)ans=max(ans,area(l[k],l[t+1]));
if(t-1>=i)ans=max(ans,area(l[k],l[t-1]));
}
}
cout<<ans<<"\n";
return 0;
}