HDU

来源:互联网 发布:windows解压war包 编辑:程序博客网 时间:2024/06/07 05:21

题目大意:

多组测试数据(t<=5),每组给你平面直角坐标系上的 n 个(1<=n<=5e4)。这n个点两两之间有一条连线,连线值为这两点的值的乘积。现在让你选一条过原点的直线,使得经过直线的线段的值的和最大。

分析:

直线绕原点旋转,尺取每个点和原点的连线和 x 轴正方向的夹角(0~2π)。即:尺取每个点进入直线上区域或下区域。

未AC代码:

#include<bits/stdc++.h>#define maxn 50050using namespace std;int n;double small=1e-7;double p=4*atan(1.0);struct point{    int x;int y;    double ang;    long long int v;}a[maxn];double Get_ang(int x,int y){    double t=(double)(y)/(double)(x);    if(x>0&&y>0)return atan(t);    if(x<0&&y>0)return p-atan(-t);    if(x<0&&y<0)return p+atan(t);    if(x>0&&y<0)return 2*p-atan(-t);    if(y==0)    {        if(x>0)return 0;        else return p;    }    if(x==0)    {        if(y>0)return p/2;        else return 3*p/2;    }}bool cmp(point a,point b){    return a.ang<b.ang;}int main(){    int t;    scanf("%d",&t);    while(t--)    {        scanf("%d",&n);        long long int up=0,down=0,temp_v;        int num=0,temp_x,temp_y;        for(int i=0;i<n;i++)        {            scanf("%d%d%lld",&temp_x,&temp_y,&temp_v);            if(temp_x==0&&temp_y==0)continue;            a[num].x=temp_x;            a[num].y=temp_y;            a[num].v=temp_v;            a[num].ang=Get_ang(a[num].x,a[num].y);            if(a[num].y>0||(a[num].y==0&&a[num].x>0))//x轴正方向上得点在up,x轴负方向上的点在down。            {                up+=a[i].v;            }            else            {                down+=a[i].v;            }            num++;        }        //printf("%lld  %lld\n",up,down);        sort(a,a+num,cmp);        long long int ans=down*up;        n=num;        int j=0;        for(int i=0;i<n;i++)        {            if(a[i].ang>p-small)            {                j=i;                break;            }        }        int i=0;        while(1)//每次循环计算第i个在下面,第j个在上面的值        {            if(i>=n||abs(a[i].ang-p)<small)break;            up-=a[i].v;down+=a[i].v;            while(1)            {                if(i>=n||a[i+1].ang-a[i].ang>small)break;                i++;                up-=a[i].v;down+=a[i].v;            }            while(1)            {                if(j>=n||a[j].ang>a[i].ang+p+small)break;                up+=a[j].v;down-=a[j].v;                j++;            }            j--;            ans=max(ans,up*down);        }         while(1)//每次循环计算第i个在下面,第j个在上面的值.2        {            if(i>=n)break;            up-=a[i].v;down+=a[i].v;            while(1)            {                if(i>=n||a[i+1].ang-a[i].ang>small)break;                i++;                up-=a[i].v;down+=a[i].v;            }            if(i>=n)i=n-1;            j=max(j,i+1);            while(1)            {                if(j>=n||a[j].ang>a[i].ang-p+small&&j<i)break;                up+=a[j].v;down-=a[j].v;                j++;                j%=n;            }            j--;            ans=max(ans,up*down);        }       /* for(int i=0;i<n-1;i++)        {            up-=a[i].v;            down+=a[i].v;            if(a[i+1].ang>p-small)            {                j%=n;                while(1)                {                    if(a[j].ang>a[i+1].ang-p-small)break;                    up+=a[j].v;                    down-=a[j].v;                    j++;                    j%=n;                }            }            else while(1)            {                if(a[j].ang>p+a[i+1].ang-small)break;                up+=a[j].v;                down-=a[j].v;                j++;                j%=n;            }            printf("%lld %lld\n",up,down);            ans=max(ans,up*down);            //printf("%lld",ans);        }*/        printf("%lld\n",ans);    }}

边界问题。

原创粉丝点击