HDU6127 Hard challenge[计算几何]

来源:互联网 发布:淘宝交易指数 构成 编辑:程序博客网 时间:2024/05/24 00:02

Hard challenge

 HDU - 6127
 


题意:

给T组数据,每组数据有一个n,代表n个点,接下来n行,每行给出一个x和y还有val,代表每个点的位置和值。两个点连起来的值等于两点的val相乘,不存在两点同时存在于一条与原点相连的线上。问从原点处划一条直线,不与这n个点相交(即点都不能存在于这条直线上),能经过最大的边和是多少。


题解:

实际上,用直线分开两边,得到的和就是等于该线的上方的权值和乘以该线的下方的权值和。

先对这n个点进行极角排序,然后将他们分开4个象限,保存所有点的权值和,根据象限,也保存该象限的前缀和,方便后面的计算。

然后开始从第一象限的点开始扫描到第四象限,每扫描到一个点,同象限在其前面(包括它自身)的权值加起来,用双指针,在其旋转180度的象限中找到一个斜率比该点要大的点,将其与该象限剩下的点的权值加起来,还有将其顺时针90度的象限的所有点的权值也加起来,因为这些地方都是在该线的左侧。

然后枚举出来的该线的答案就是等于  当前的权值*(sum-当前的权值)。将所有点按象限都扫一次,就可以得到最大值了。



#pragma comment(linker, "/STACK:102400000,102400000")#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<string>#include<algorithm>#include<queue>#include<stack>#include<set>#include<map>#include<vector>using namespace std;typedef long long ll;const int N=5e4+5;ll sum[5][N];vector<int>vc[5];int nx[]={0,4,1,2,3};int fan[]={0,3,4,1,2};struct point{    int x,y,val;    point (int xx=0,int yy=0,int v=0):x(xx),y(yy),val(v){}}p[N];ll cross(const point &p1,const point &p2,const point &q1,const point &q2){    return (ll)(q2.y-q1.y)*(p2.x-p1.x)-(ll)(q2.x-q1.x)*(p2.y-p1.y);}bool cmp(const point &a,const point &b){    if (!a.y && !b.y && (ll)a.x*b.x<=0)        return a.x>b.x;    if (!a.y && a.x>=0 && b.y)        return 1;    if (!b.y && b.x>=0 && a.y)        return 0;    if ((ll)b.y*a.y<=0)        return a.y>b.y;    point one;    one.y=one.x=0;    return cross(one,a,one,b)>0 || (!cross(one,a,one,b) && a.x<b.x);}bool check(const point &a,const point &b){    point np(-a.x,-a.y);    return !cmp(np,b);}void push(int id,int i,int val){    vc[id].push_back(i);    sum[id][vc[id].size()]=sum[id][vc[id].size()-1]+val;}int main(){int T;scanf("%d",&T);while (T--){    int n;    scanf("%d",&n);    for (int i=0 ; i<n ; ++i)            scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].val);        sort(p,p+n,cmp);        for (int i=0 ; i<=4 ; ++i)        {            vc[i].clear();            for (int j=0 ; j<=n ; ++j)                sum[i][j]=0;        }        ll s=0;        for (int i=0 ; i<n ; ++i)        {            if (p[i].x>=0 && p[i].y>=0)                push(1,i,p[i].val);            else if (p[i].x<0 && p[i].y>=0)                push(2,i,p[i].val);            else if (p[i].x<0 && p[i].y<0)                push(3,i,p[i].val);            else                push(4,i,p[i].val);            s+=p[i].val;        }        ll mx=0;        for (int i=1 ; i<=4 ; ++i)        {            if (!vc[i].size())                continue;            for (int j=0,k=0 ; j<vc[i].size() ; ++j)            {                ll tmp=sum[nx[i]][vc[nx[i]].size()]+sum[i][j+1];                while (k<vc[fan[i]].size() && check(p[vc[i][j]],p[vc[fan[i]][k]]))                    ++k;                tmp+=sum[fan[i]][vc[fan[i]].size()]-sum[fan[i]][k];                mx=max(tmp*(s-tmp),mx);            }        }        printf("%lld\n",mx);}return 0;}/*104-5 2 100-2 -3 100100000000 1000000000 10100000000 999999999 921 1 11 -1 131 1 11 -1 10-1 0 10042 1 10-4 -1 20-3 -4 30-2 -5 403-1 2 103 -1 201 -5 30*/

原创粉丝点击