bzoj2338: [HNOI2011]数矩形

本文探讨了一种新颖的方法来解决矩形对角线的问题,通过判断线段中点是否重合且长度相等来寻找可能构成矩形的对角线组合。文章介绍了一个基于计算几何的解决方案,并提供了具体的实现思路与代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题解

  这题需要开一点脑洞,我只想到了长度相等但是并没有想到中点重合..
  首先进行O(n2)的预处理,处理出n(n1)2条线段作为备选对角线。
  如果两条线段中点重合且长度相等,它们就能组成矩形
  证明的话,我想想
  可以利用直角三角形的中线等于斜边的一半,根据初中几何,这玩意的逆定理也是成立的。然后证明就简单了,我就不写了。
  然后你就按照长度为第一关键字,中点为第二关键字进行排序。
  排序后每条线段暴力往前扫描所有和它长度相等且中点重合的对角线,叉积统计下答案。
  这样复杂度不会退化吗?
  蒟蒻并不会证明,但是蒟蒻发现如果故意构造一些长度相等且中点重合的线段,也就是菊花状,那么长度相等且中点重合的线段的组的大小就会变大,但同时组数会减少。
  如果强行增大组数,那么每一组的大小就会变少。
  我们设组的大小是size,那么组数就是n2size
  程序的复杂度的一个非常宽松的上界显然是O(size2n2size)=O(size×n2)
  想要最大化这个数,显然size要加到最大,但是刚才已经讨论过了,size最大的时候就是N,而且这个时候就是菊花图,菊花图的复杂度已经知道是O(N2)
  因此直觉告诉我这个算法不会太慢

代码

//计算几何 
#include <cstdio>
#include <algorithm>
#define maxn 1500
using namespace std;
typedef long long ll;
ll N, x[maxn], y[maxn];
struct segment{ll len, x, y, id1, id2;}seg[maxn*maxn];
bool operator<(segment l1, segment l2)
{
    if(l1.len==l2.len)
    {
        if(l1.x==l2.x)return l1.y<l2.y;
        return l1.x<l2.x;
    }
    return l1.len<l2.len;
}
bool cmp(segment l1, segment l2)
{return l1.x==l2.x and l1.y==l2.y and l1.len==l2.len;}
ll gets(segment l1, segment l2)
{
    ll x1=x[l1.id1]-x[l1.id2], y1=y[l1.id1]-y[l1.id2], x2=x[l2.id1]-x[l2.id2],
       y2=y[l2.id1]-y[l2.id2];
    return abs(x1*y2-x2*y1);
}
ll sqr(ll x){return x*x;}
int main()
{
    freopen("in.txt","r",stdin);
    ll i, j, ans=0, tot=0;
    scanf("%lld",&N);
    for(i=1;i<=N;i++)scanf("%lld%lld",x+i,y+i);
    for(i=1;i<=N;i++)for(j=i+1;j<=N;j++)
    {
        tot++;
        seg[tot].id1=i, seg[tot].id2=j;
        seg[tot].x=x[i]+x[j], seg[tot].y=y[i]+y[j];
        seg[tot].len=sqr(x[i]-x[j])+sqr(y[i]-y[j]);
    }
    sort(seg+1,seg+tot+1);
    for(i=1;i<=tot;i++)
        for(j=i-1;j and cmp(seg[j],seg[i]);j--)
        {
            ans=max(ans,gets(seg[j],seg[i]));
        }
    printf("%lld",ans>>1);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值