1 条题解

  • 0
    @ 2026-5-7 17:00:39

    双倍经验,甚至样例、数据范围完全一致。

    思路

    矩形的判定:对角线互相平分且长度相等的四边形为矩形

    若两条线段长度相等且中点重合,则存在一个以这两条线段为对角线的矩形。

    枚举每一对点作为线段的两端,存储线段两端坐标、中点坐标以及长度。

    将所有线段以长度为第一关键字、中点横坐标为第二关键字、中点纵坐标为第三关键字排序。

    对于每一条线段,往前枚举与其长度相等且中点重合的线段并求出对应矩形的面积,更新答案。

    :::info[时间复杂度]{open}

    排序复杂度为 O(n2logn)\mathcal{O}(n^2 \log n)

    枚举矩形的复杂度与矩形个数同阶。

    有如下定理:在平面上的 nn 个点中任选三个点构成一个三元组 (A,B,C)(A,B,C),线段 ABAB 与线段 ACAC 有一夹角。在所有夹角中,任意一个特定的角度出现的次数为 O(n2logn)\mathcal{O}(n^2 \log n) [1]^{\textup{\textmd{\textsf{[1]}}}}

    若三元组 (A,B,C)(A,B,C) 满足 ABACAB \perp AC,则称其为「直角三元组」‌。

    由上述定理,「直角三元组」‌的个数为 O(n2logn)\mathcal{O}(n^2 \log n)

    任意两个矩形不可能有三个相同的顶点,即一个「直角三元组」‌至多对应一个矩形。因此,矩形的个数亦为 O(n2logn)\mathcal{O}(n^2 \log n)

    故总复杂度为 O(n2logn)\mathcal{O}(n^2 \log n)

    :::

    Code

    为了避免精度问题,对于中点坐标,可以存储横纵坐标的两倍;对于线段长度,可以存长度的平方。

    注意计算矩形面积时会爆 long long,需要使用 __int128 并手写开根。

    #include<bits/stdc++.h>
    #define int long long
    #define lint __int128
    
    const int N=1510; 
    
    using namespace std;
    
    int n,tot,lst,a[N][2],ans;
    
    struct L{
    	int x,y,_x,_y,mx,my,len;
    	bool operator<(const L &b)const{
    		if(len^b.len)return len<b.len;
    		if(mx^b.mx)return mx<b.mx;
    		return my<b.my;
    	}
    }c[N*N];
    
    inline int read(){
    	int ret=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9')ret=ret*10+(ch&15),ch=getchar();
    	return ret*f;
    }
    
    L _init(int x,int y,int _x,int _y){
    	int mx=x+_x,my=y+_y,len=(_x-x)*(_x-x)+(_y-y)*(_y-y);
    	return (L){x,y,_x,_y,mx,my,len};
    }
    
    bool _chk(L c1,L c2){
    	return !((c1.mx^c2.mx)||(c1.my^c2.my)||(c1.len^c2.len));
    }
    
    int _sqrt(lint x){
    	int l=0,r=1e18;
    	while(l<=r){
    		int mid=(l+r)>>1;
    		if((lint)mid*mid==x)return mid;
    		if((lint)mid*mid<x)l=mid+1;
    		else r=mid-1;
    	}
    }
    
    lint _calc(int x,int y,int _x,int _y){
    	return (lint)(_x-x)*(_x-x)+(lint)(_y-y)*(_y-y);
    }
    
    signed main(){
    	n=read();
    	for(int i=1;i<=n;i++)a[i][0]=read(),a[i][1]=read();
    	for(int i=1;i^n;i++)for(int j=i+1;j<=n;j++)c[++tot]=_init(a[i][0],a[i][1],a[j][0],a[j][1]);
    	sort(c+1,c+tot+1);
    	for(int i=1;i<=tot;i++){
    		if(!_chk(c[i],c[lst]))lst=i;
    		for(int j=lst;j^i;j++){
    			int s=_sqrt(_calc(c[i].x,c[i].y,c[j].x,c[j].y)*_calc(c[i].x,c[i].y,c[j]._x,c[j]._y));
    			ans=max(ans,s);
    		}
    	}
    	printf("%lld\n",ans);
    	return 0;
    }
    

    参考文献

    [1] PACH J, SHARIR M. Repeated angles in the plane and related problems[J]. Journal of Combinatorial Theory, Series A, 1992, 59(1): 12-22.

    • 1

    信息

    ID
    10549
    时间
    6000ms
    内存
    164MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者