[BZOJ2338][HNOI2011]数矩形(计算几何)

来源:互联网 发布:有数学题的软件 编辑:程序博客网 时间:2024/05/19 04:03

考虑两条线段能够成为矩形的两对角线的条件:两条线段互相平分且相等。
首先预处理出所有点两两构成线段的中点和长度,然后以中点的x坐标为第一关键字,中点的y坐标为第二关键字,线段长度为第三关键字将线段排序。
这样,所有中点坐标和长度都相等的线段集合就是一段连续的区间。
在合法的集合内,可枚举两条线段,用叉积判断面积。
代码:

#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;inline int read() {    int res = 0; bool bo = 0; char c;    while (((c = getchar()) < '0' || c > '9') && c != '-');    if (c == '-') bo = 1; else res = c - 48;    while ((c = getchar()) >= '0' && c <= '9')        res = (res << 3) + (res << 1) + (c - 48);    return bo ? ~res + 1 : res;}typedef long long ll;const int N = 1505, M = 225e4 + 5;struct cyx {    int x1, y1, x2, y2, cx, cy; ll len;    cyx() {}    cyx(int _x1, int _y1, int _x2, int _y2, int _cx, int _cy, ll _len) :        x1(_x1), y1(_y1), x2(_x2), y2(_y2), cx(_cx), cy(_cy), len(_len) {}} a[M];inline bool comp(const cyx &a, const cyx &b) {    if (a.cx != b.cx) return a.cx < b.cx;    if (a.cy != b.cy) return a.cy < b.cy;    return a.len < b.len;}ll area(int x, int y) {    int x1 = a[y].x1 - a[x].x1, y1 = a[y].y1 - a[x].y1,        x2 = a[y].x2 - a[x].x1, y2 = a[y].y2 - a[x].y1;    return abs(1ll * x1 * y2 - 1ll * x2 * y1);}int n, m, X[N], Y[N]; ll Ans;int main() {    int i, j, k; n = read();    for (i = 1; i <= n; i++) X[i] = read(), Y[i] = read();    for (i = 1; i < n; i++) for (j = i + 1; j <= n; j++)        a[++m] = cyx(X[i], Y[i], X[j], Y[j], X[i] + X[j], Y[i] + Y[j],            1ll * (X[i] - X[j]) * (X[i] - X[j]) + 1ll *            (Y[i] - Y[j]) * (Y[i] - Y[j]));    sort(a + 1, a + m + 1, comp); for (k = 1; k <= m;) {        int nxt = k; while (a[k].cx == a[nxt].cx && a[k].cy == a[nxt].cy            && a[k].len == a[nxt].len && nxt <= m) nxt++;        for (i = k; i < nxt; i++) for (j = i + 1; j < nxt; j++)            Ans = max(Ans, area(i, j)); k = nxt;    }    cout << Ans << endl;    return 0;}
原创粉丝点击