2017 Multi-University Training Contest

来源:互联网 发布:windows安装 nvidia 编辑:程序博客网 时间:2024/06/07 00:51

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


题意:

  给你n个点的坐标,每个点有一个val值,两两之间有一条连线,这条线的价值为两个点的val值的乘积,保证不会有连线穿过原点。现在有一条经过原点的直线,要你求穿过的线价值总和的最大值。

思路:

  直接进行极角排个序,然后进行扫描,从水平,然后旋转180度,每次把直线两边的点分成两部分,把值加起来相乘,就可以计算出一个最大值,因为题目说了任意直线不是经过原点的,每次碰到的肯定是一个点,而不是多个点。

代码:

#include<bits/stdc++.h>#define maxn 50005#define ll long longusing namespace std;const double PI = acos(-1.0);struct node{    ll x,y,val;    double ang;}a[maxn];bool cmp(node x,node y){    return x.ang < y.ang;}int main(){    ll m,n,T;    scanf("%lld",&T);    while(T--){        scanf("%lld",&n);        for(ll i = 1;i <= n;i++){            scanf("%lld %lld %lld",&a[i].x,&a[i].y,&a[i].val);            if(a[i].x){                a[i].ang = atan(1.0 * a[i].y / a[i].x);            }else{                a[i].ang = PI / 2;            }        }        ll l,r;        l = r = 0;        sort(a + 1,a + 1 + n,cmp);        for(ll i = 1;i <= n;i++){            if(a[i].x >= 0){                r += a[i].val;            }else{                l += a[i].val;            }        }        ll ans = l * r;        for(ll i = 1;i < n;i++){            if(a[i].x >= 0){                r -= a[i].val;                l += a[i].val;            }else{                r += a[i].val;                l -= a[i].val;            }            if(ans < l * r){                ans = l * r;            }        }        printf("%lld\n",ans);    }    return 0;}
原创粉丝点击