HDU 6127 Hard challenge (極角排序+二分, 2017 Multi-Univ Training Contest 7)

Problem

Problem Link

There are n points on the plane, and the ith points has a value vali , and its coordinate is (xi,yi ). It is guaranteed that no two points have the same coordinate, and no two points makes the line which passes them also passes the origin point. For every two points, there is a segment connecting them, and the segment has a value which equals the product of the values of the two points. Now HazelFan want to draw a line throgh the origin point but not through any given points, and he define the score is the sum of the values of all segments that the line crosses. Please tell him the maximum score.

Idea

在已知直線將座標系分割爲兩部分時,求任意左上部分點到右下部分點的線段價值和,可以等效地看作是 val()×val() 。當點有序時,利用前綴和維護來求價值和的複雜度爲 O(1)

顯然由於通過過原點直線分割圖形,可以將所有點按照極角排序。通過枚舉點 i (x, y) ,假設直線恰好通過點 i ,二分獲取最大的在極角排序中小於點 i 關於原點對稱點 (-x, -y) (題目保證不會有任意兩點的連線過原點)。則直接可以求當前劃分所產生的價值和(當然,需要區分 i 點在左上或右下的情況,顯然 i 過直線是不會產生價值,即總價值縮水,微偏移直線的斜率即可最大化當前枚舉情況的最優。)

當然,不使用二分,利用雙指針的做法來獲取左上點與右下點的分界也可。

HINT: 由於此題的座標取值較大,可能出現中間過程爆 int 的可能,最好將座標 x , y 取 long long 。:joy: 沒注意在這個問題上 WA 了兩發。

Code

#include<bits/stdc++.h>
using namespace std;
const int N = 50000 + 10;
int T, n, pre[N];
struct point {
    long long x, y, val;
} p[N], ori, np;
double cross(const point &p1, const point &p2, const point &q1, const point &q2) {
    return (q2.y - q1.y)*(p2.x - p1.x) - (q2.x - q1.x)*(p2.y - p1.y);    
}
bool cmp(const point &a, const point &b) 
{
    if (a.y == 0 && b.y == 0 && a.x*b.x <= 0)return a.x>b.x;
    if (a.y == 0 && a.x >= 0 && b.y != 0)return true;
    if (b.y == 0 && b.x >= 0 && a.y != 0)return false;
    if (b.y*a.y <= 0)return a.y>b.y;
    return cross(ori,a,ori,b) > 0 || (cross(ori,a,ori,b) == 0 && a.x < b.x);    
}
bool jug(int idx, int mid) {
    np.x = -p[idx].x;    np.y = -p[idx].y;
    if(cmp(np, p[mid]) == true)    return false;
    return true;
}
int bs(int idx, int l, int r, int ans) {
    int mid;
    while(l <= r) {
        mid = (l+r) / 2;
        if(jug(idx, mid)) {
            l = mid + 1, ans = mid;
        } else {
            r = mid - 1;
        }
    }
    return ans;
}
long long calc(long long part) {
    return part * (pre[n] - part);
}
long long solve()
{
    long long ans = 0;
    for(int i=1, lft, rgt;i<=n;i++)
    {
        if(p[i].y < 0) {
            lft = bs(i, 1, i-1, 0);
            ans = max(ans, calc(pre[i] - pre[lft]));
            ans = max(ans, calc(pre[i-1] - pre[lft]));
        } else {
            rgt = bs(i, i+1, n, i);
            ans = max(ans, calc(pre[rgt] - pre[i]));
            ans = max(ans, calc(pre[rgt] - pre[i-1]));
        }
    }
    return ans;
}
int main()
{
    ori.x = ori.y = 0;
    scanf("%d", &T);
    while(T-- && scanf("%d", &n)!=EOF)
    {
        for(int i=1;i<=n;i++)
            scanf("%lld %lld %lld", &p[i].x, &p[i].y, &p[i].val);
        sort(p+1, p+n+1, cmp);

        for(int i=1;i<=n;i++) {
            pre[i] = pre[i-1] + p[i].val;
        }

        printf("%lld\n", solve());
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章