[BZOJ2338][HNOI2011]数矩形

题目

暴力枚举 O(N4) 很简单吧,但是会T,可能一分都拿不到
考虑由三个点推出第四个点,我们枚举三个点看它们是不是构成直角且第四个点存在,不考虑数据结构(hash,map)带来的复杂度,是 O(N3) 卡卡常数可以得到20分。
枚举点我们会浪费直角这个条件,不优,根据初中数学,我们知道对角线和中点可以定下一个矩形,那我们就对每两个点存它们的中点和对角线长度(这步骤 O(N2) ),然后hash或者sort,就可以在点的周围找可以构成矩形的点了,总的复杂度 O(N2C) (C为hash常数)或 O(N2logN) ,可以过掉100%的数据,我第一次hash常数不够优秀,导致T了,然后换成sort就过了。。。

代码:

/**************************************************************
    Problem: 2338
    User: waz
    Language: C++
    Result: Accepted
    Time:1840 ms
    Memory:72092 kb
****************************************************************/

#include <cstdio>
#include <algorithm>
const int MaxN = 1510;
struct Point {
    int X, Y;
    Point operator + (Point That) {
        return (Point) { X + That.X, Y + That.Y };
    }
    Point operator - (Point That) {
        return (Point) { X - That.X, Y - That.Y };
    }
    bool operator == (Point That) const {
        return X == That.X && Y == That.Y;
    }
    bool operator < (Point That) const {
        return X < That.X || (X == That.X && Y < That.Y);
    }
}   P[MaxN];
struct Line {
    Point A, B;
    Point Mid;
    long long Dist;
    bool operator == (Line That) const {
        return Mid == That.Mid && Dist == That.Dist;
    }
    bool operator < (Line That) const {
        return Mid < That.Mid || (Mid == That.Mid && Dist < That.Dist);
    }
}   L[MaxN * MaxN];
int Cnt, N;
long long Dist(Point A, Point B) {
    return (long long)(A.X - B.X) * (A.X - B.X) + (long long)(A.Y - B.Y) * (A.Y - B.Y);
}
void Link(Point A, Point B) {
    L[++Cnt] = (Line) {A, B, A + B, Dist(A, B)};
}
long long Cross(Point A, Point B) {
    return (long long)A.X * B.Y - (long long)B.X * A.Y;
}
long long Abs(long long X) {
    return X < 0 ? -X : X; 
}
long long Ans;
int main() {
    scanf("%d", &N);
    for (int i = 1; i <= N; i++)
        scanf("%d%d", &P[i].X, &P[i].Y);
    /*Link((Point){1, 1}, (Point){3, 3});
    Link((Point){1, 3}, (Point){3, 1});
    printf("%d\n", L[1] < L[2]);*/
    for (int i = 1; i <= N; i++)
        for (int j = i + 1; j <= N; j++)
            Link(P[i], P[j]);
    std :: sort(L + 1, L + Cnt + 1);
    /*puts("\n\n\n");
    for (int i = 1; i <= Cnt; i++)
        printf("%d %d %I64d\n", L[i].Mid.X, L[i].Mid.Y, L[i].Dist);*/
    Line *First = L + 1;
    for (int i = 2; i <= Cnt; i++) {
        Line *Ln = L + i;
        if (*First == *Ln) {
            long long Area;
            for (Line *I = First; I < Ln; I++) {
                Area = Abs(Cross(Ln -> A - I -> A, Ln -> B - I -> A));
                if (Ans < Area) Ans = Area;
            }
            //printf("%I64d\n", Area);
        }
        else First = Ln;
    }
    printf("%lld\n", Ans);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值