【HNOI2011】数矩形

HNOI2011

bzoj2338

2019.2.28更新:复杂度是O(n^2.5),证明见评论区,感谢 @HigHwindEx 指正


最近总是在找些水题做QAQ

说这个题之前,我想先说一些别的事…暑假集训的时候一个叫小兔子的同(神)学(犇)提出的问题:给出一堆点的坐标,求这些点所围成的正方形的个数(可以斜着)。

不得不说当时并没有怎么在意,结果前两天在noip吧里见到有普及组大神用n^3的算法解此题……然后我在回帖里找到了正解…顺便找到了此题……

这大概也是我做的第一个计算几何的题,当时并没有想这么多就开始写了,导致代码很难调所以重新打了一份,还写了个向量的加减之类的…

此题有O(n^2 logn)算法,做法是枚举n个点所构成的所有边O(n2),然后按第一关键字为中点坐标,第二关键字为边的长度进行排序(O(n2 logn)),初中生知识可知:中点相同并且长度相等的两条边必然是一个矩形的两条对角线。然后枚举计算即可。

一开始傻X一样double存,各种被误差恶心,然后成功溢出……顺便学会了long double…(scanf("%Lf",&a);)在codevs上交总是90分,感觉是精度有问题然后去百度…结果发现中点什么的只需要比较大小为何我要存浮点数(╯‵□′)╯︵┻━┻改成long long…各种恶心的浮点数问题就随之而去了……然后发现自己计算的时候没有计算完全,改了后A了。

第一次打计算几何的代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int size=1510;

struct point{
	long long x,y;
	long long dist()
	{
		return x*x+y*y;
	}
}p[size];
point operator +(const point &a,const point &b)
{
	return (point){a.x+b.x,a.y+b.y};
}
point operator -(const point &a,const point &b)
{
	return (point){a.x-b.x,a.y-b.y};
}
bool operator ==(const point &a,const point &b)
{
	return a.x==b.x&&a.y==b.y;
}
bool operator !=(const point &a,const point &b)
{
	return (a.x!=b.x)||(a.y!=b.y);
}
bool operator <(const point &a,const point &b)
{
	if(a.x!=b.x) return a.x<b.x;
	return a.y<b.y;
}

struct edge{
	point l,r,mid;
	long long len;
}l[2250010];

bool operator <(const edge &a,const edge &b)
{
	if(a.mid!=b.mid) return a.mid<b.mid;
	return a.len<b.len;
}

int tot=0;

int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld%lld",&p[i].x,&p[i].y);
		for(int j=1;j<i;j++)
		{
			l[++tot]=(edge){p[i],p[j],(p[i]+p[j]),((p[i]-p[j])).dist()};
		}		
	}
//	build(n);
	sort(l+1,l+1+tot);
/*	for(int i=1;i<=tot;i++)
	{
		int tot=i;
			printf("%lld %lld %lld %lld %lld %lld %lld\n",l[tot].l.x,l[tot].l.y,l[tot].r.x,l[tot].r.y,l[tot].mid.x,l[tot].mid.y,l[tot].len);			
	}*/
	long long ans=0;
	for(int i=1,k=1;i<=tot;i++)
	{
		for(int j=k;j<i;j++)
		if(l[i].mid==l[j].mid&&l[i].len==l[j].len)
		{
			ans=max(ans,(long long) ( sqrt( (l[i].l-l[j].l).dist() ) *sqrt( (long double) (l[i].l-l[j].r).dist() )+0.5) );
		//	puts("fuck");
		}
		else k=i;
	}
	printf("%lld",ans);
	return 0;
}
/*
8
-2 3
-2 -1
0 3
0 -1
1 -1
2 1
-3 1
-2 1
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值