杭电暑期多校集训— hard challenge

Hard challenge

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 579    Accepted Submission(s): 235


Problem Description
There are  n  points on the plane, and the  i th 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.
 

Input
The first line contains a positive integer  T(1T5) , denoting the number of test cases.
For each test case:
The first line contains a positive integer  n(1n5×104) .
The next  n  lines, the  i th line contains three integers  xi,yi,vali(|xi|,|yi|109,1vali104) .
 

Output
For each test case:
A single line contains a nonnegative integer, denoting the answer.
 

Sample Input
  
  
2 2 1 1 1 1 -1 1 3 1 1 1 1 -1 10 -1 0 100
 

Sample Output
  
  
1 1100
 这个题可以理解为现在给你n个点,每个点都有相应的权值,你可以任意连接两个点形成线段,线段 的权值为两个端点的权值之积,所有的线段都不会经过原点。现在你找一条经过原点的直线,直线的 权值为经过的线段的权值之和,最后输出这条直线可能最大的权值。
解题思路




                    P1                   P2




                 P3                         P4 


                                  Ans=P1*(P2+P4)+P3*(P2+P4)
                                      =(P1+P3)*(P2+P4)




如图所示,蓝色线为由Y轴旋转而来,两边的点互相配对,此时形成的所有的线段的权值之和即为当 所求直线在这个位置的权值,接下来只需要求出当这个直线在不同位置的时的权值并找出最大值即可。
#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#define PI 3.1415926
using namespace std;
struct point
{
    int x,y,val;
    double angle;
} P[50005];

bool cmp(point p1,point p2)
{
    return p1.angle<p2.angle;
}

int main()
{
    int n,cases;
    long long ans,left_sum,right_sum;        //left_sum和right_sum不会爆int但是相乘会爆int
    scanf("%d",&cases);
    while(cases--)
    {
        scanf("%d",&n);
        for(int i=0; i<n; ++i)
        {
            scanf("%d%d%d",&P[i].x,&P[i].y,&P[i].val);
            if(P[i].x==0)           //这里对x=0进行特判,除数不能为0
            {
                if(P[i].y>0)
                    P[i].angle=PI/2.0;
                Else
                P[i].angle=-PI/2.0;
            }
            else
                P[i].angle=atan(P[i].y*1.0/P[i].x);
        }
        sort(P,P+n,cmp);
        ans=1;
        left_sum=right_sum=0;
        //初始先以y轴对做表面进行划分
        for(int i=0; i<n; ++i)
        {
            if(P[i].x>=0)
                right_sum+=P[i].val;   //出现在y轴右侧(包含y轴)的点全部添加到右区间
            else
                left_sum+=P[i].val;
        }
        //直线左侧的点一定能和直线右侧的点连成线段,那么直线两端任意两点权值积的和,就是两个区间权值和的积
        ans=left_sum*right_sum;
        for(int i=0; i<n; ++i)  //根据极角排序的顺序,遍历每一个点,然后把这个点从它之前所在的区间里剔除加到另一个区间
        {
            if(P[i].x>=0)                   //原来在右区间,从右区间剔除
            {
                right_sum-=P[i].val;
                left_sum+=P[i].val;
            }
            else                            //原来在左区间,从左区间剔除
            {
                right_sum+=P[i].val;
                left_sum-=P[i].val;
            }
            ans=max(ans,left_sum*right_sum);
        }
        cout<<ans<<endl;
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值