HDU 6127 Hard challenge(几何)

来源:互联网 发布:什么叫知世故而不世故 编辑:程序博客网 时间:2024/06/07 11:55

【题目链接】hdu-6127

【题意】平面直角坐标系上有n个整点,第i个点有一个点权v,坐标为(xi,yi),其中不存在任意两点连成的直线经过原点。这些整点两两之间连有一条线段,线段的权值为其两端点的权值之积。你需要作一条过原点而不过任意一个给定整点的直线,使得和这条直线相交的线段的权值和最大。

【样例】

Sample Input
221 1 11 -1 131 1 11 -1 10-1 0 100
 

Sample Output
11100

【分析】

       首先,按角度分块之后,可以知道每块里任意取线段,结果是一样的。因此只要每次做原点到某一个输入点的线段,将输入点视作在某一侧就行了。

       bestcoder题解是这样说的:对于一条直线,线段权值和实际上就等于其两边点权和的乘积,所以把所有点按极角排个序,然后扫一圈就好了。

       其中,“线段权值和实际上就等于其两边点权和的乘积“这句话是此题解法的核心,将对所有线的处理转化为了对点的处理,时间复杂度立刻降到合理范围。再加上按极角排序,所以每次更新两侧的点不需要重新遍历一遍所有点,稍微处理上一次的数据就可以得到新的结果。

       我的做法是:将点按极角排序后,对于每个点,设极角为c,每次将极角>=c&&极角-c<π的点的值加到L,将剩余点的值加入R,每次记录L范围外的下一个点为flg。当每次更新时,从L中减去上一个点的值,然后从点flg开始,不断加入符合条件的值,并更新flg。要注意flg会从n转回0,这里要处理一下。

       题解真是说的一点都不清楚,我说的也一点都不清楚= =

【代码】

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<cmath>using namespace std;#define maxn 50005#define pai 3.141592653int n;long long sum,ans,l,r,flg;struct node{    int x,y,v;    double c;};node a[maxn];bool cmp(node a,node b){    return a.c<b.c;}double calc(int x,int y){//计算极角    double c;    int ax=abs(x),ay=abs(y);    if(x>=0&&y>=0){        if(x==0)            c=pai/2;        else            c=atan(ay*1.0/ax);    }    else if(x<0&&y>=0)        c=pai-atan(ay*1.0/ax);    else if(x<=0&&y<0){        if(x==0)            c=1.5*pai;        else            c=pai+atan(ay*1.0/ax);    }    else if(x>0&&y<0)        c=2*pai-atan(ay*1.0/ax);    return c;}void pre(){    double c=a[0].c;    for(int i=0;i<n; i++){        if(a[i].c-c>pai){            flg=i;            break;        }        if(a[i].c>=c)            l+=a[i].v;    }    r=sum-l;    ans=max(ans,l*r);}int main(){    int T;    scanf("%d",&T);    while(T--){        scanf("%d",&n);        sum=0,ans=0,l=0,r=0,flg=n-1;        for(int i=0;i<n;i++){            scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].v);            sum+=a[i].v;            a[i].c=calc(a[i].x,a[i].y);        }        sort(a,a+n,cmp);        pre();//扫一遍,处理出两侧点权和        double c,m;        for(int i=1;i<n;i++){            c=a[i].c;            l-=a[i-1].v;            for(int j=flg;j<=2*n;j++){                if(j>=n)                    m=a[j-n].c+2*pai;//*                else                    m=a[j].c;                if(m-c>=pai)                    break;                if(m-c<pai){                    if(j>=n)                        l+=a[j-n].v;//*                    else                        l+=a[j].v;                    flg++;                }            }            r=sum-l;            ans=max(ans,l*r);        }        cout<<ans<<endl;    }    return 0;}