Hard challenge

来源:互联网 发布:java开发笔试题及答案 编辑:程序博客网 时间:2024/06/08 05:15

HDU 6127
这里写图片描述

给定n个点,每个点有权值,两两之间连线不过远点,现在要一条过远点的直线把点分成两个集合,使得两边的和的乘积尽量大。
这题直接极角排序,然后枚举每个点,维护对面的点就可以了,复杂度为nlogn。
唯一要注意的就是枚举的点可以属于两边中的任意一边

#include <bits/stdc++.h>using namespace std;const int maxn = 50010;const double eps = 1E-9;struct Point {    long long x, y, v;    Point() {x = y = v = 0;}    Point(int xx, int yy, int vv): x(xx), y(yy), v(vv) {}    void read() {        scanf("%lld %lld %lld", &x, &y, &v);    }    double operator^(const Point &b) const {        return x*b.y-y*b.x;    }};Point a[maxn];int n, m, sum, t, l, r;long long ans;int get(Point a) {    if (a.x > 0 && a.y >= 0) return 1;    if (a.x <= 0 && a.y > 0) return 2;    if (a.x < 0 && a.y <= 0) return 3;    return 4;}int sgn(double x) {    if (fabs(x) < eps) return 0;    if (x < 0) return -1;    else return 1;}double sqr(double x) {return x*x;}double dist(Point a, Point b) {    return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}bool _cmp(Point p1, Point p2) {    if (get(p1) > get(p2)) return true;    else if (get(p1) < get(p2)) return false;    double tmp = p1^p2;    if (sgn(tmp) < 0) return true;    else return false;}int main() {    int T;    scanf("%d", &T);    while (T--) {        sum = 0;        scanf("%d", &n);        for (int i = 1; i <= n; i++) {            a[i].read();            sum += a[i].v;        }        sort(a+1, a+1+n, _cmp);        for (l = n; l >= 1; l--) if (sgn(a[1]^a[l]) <= 0) break;        t = 0;        for (int i = 1; i <= l; i++) t += a[i].v;        l++;        if (l == n+1) l = 1;        ans = 1LL*t*(sum-t);        ans = max(ans, 1LL*(t-a[1].v)*(sum-t+a[1].v));        for (int i = 2; i <= n; i++) {            t = t-a[i-1].v;            while (l != i && sgn(a[i]^a[l]) <= 0) {                t = t+a[l].v;                l++;                if (l > n) l = 1;            }            ans = max(ans, 1LL*t*(sum-t));            ans = max(ans, 1LL*(t-a[i].v)*(sum-t+a[i].v));        }        printf("%lld\n", ans);    }   }
原创粉丝点击