hdu 6127 Hard challenge

来源:互联网 发布:金鼎智赢交易软件 编辑:程序博客网 时间:2024/06/05 18:23

Problem

acm.hdu.edu.cn/showproblem.php?pid=6127

Meaning

平面上有 n 个不重合的点,任意三点不共线,任意两点所在直线不经原点。
每个点有个 value,任意两个点连出的线段的 value 是该两点 value 的乘积。
现从原点引出一条直线,要不经过任意给出的点,每穿过一条线段,就得到这条线段的 value。问能取得的最大的 value。

Analysis

对所有的点按角度排序(极角排序,或按斜率排),n 个点被直线分隔在两个半平面内,记其中一半的总 value 为 L,另一半的为 R,则候选解为 L * R。
枚举直线的斜率,每扫过一个点,就把它从原来的那一半中去除,而加到另一半中,更新答案。
(我是用斜率排序,枚举斜率时只枚举 180,用了一个特殊点判断扫描结束。去掉这个判断也能过)

Code

#include <cstdio>#include <algorithm>using namespace std;const int N = 50000;struct point{    long long x, y, v;    // 按斜率升序排    bool operator < (const point &rhs) const    {        // 如果点在 y 轴左边        // 要临时把它关于原点对称到 y 轴右边        long long ax = x, ay = y, bx = rhs.x, by = rhs.y;        if(x < 0)            ax = -x, ay = -y;        if(rhs.x < 0)            bx = -rhs.x, by = -rhs.y;        return ay * bx < by * ax;    }} p[N], terminal;int main(){    // terminal 是一个在 y 轴正半轴上的点    terminal.x = 0;    terminal.y = 1;    int T;    scanf("%d", &T);    while(T--)    {        int n;        scanf("%d", &n);        for(int i = 0; i < n; ++i)            scanf("%I64d%I64d%I64d", &p[i].x, &p[i].y, &p[i].v);        sort(p, p + n);        long long L = 0, R = 0;        // 初始时按 y 轴来分点        // y 轴左边的算入 L        // y 轴右边的算入 R        // y 轴上的,正半轴算 L,负半轴算 R(因为逆时针扫)        for(int i = 0; i < n; ++i)            if(p[i].x < 0)                L += p[i].v;            else if(p[i].x > 0)                R += p[i].v;            else if(p[i].y > 0)                L += p[i].v;            else                R += p[i].v;        long long ans = L * R;        // 枚举扫过的点        for(int i = 0; i < n; ++i)        {            if(p[i].x < 0)            {                L -= p[i].v;                R += p[i].v;            }            else if(p[i].x > 0)            {                L += p[i].v;                R -= p[i].v;            }            else if(p[i].y > 0)            {                L -= p[i].v;                R += p[i].v;            }            else            {                L += p[i].v;                R -= p[i].v;            }            ans = max(ans, L * R);            // 如果超过了 terminal 点            // 则扫描结束            // (去掉也能过)            if(terminal < p[i])                break;            else if(!(p[i] < terminal))                break;        }        printf("%I64d\n", ans);    }    return 0;}
原创粉丝点击