HDU 6127 Hard challenge(几何 多校第七场)

  • 题目大意

    平面上有n个点,每个点有一个价值,每两个点之间都有一条线段,定义线段的值为两个点价值的乘积,现在让你找一条过原点的直线(直线不经过任何一个节点),将这条直线所经过的所有线段的值求和,问最大的和是多少.

  • 分析

    我们容易知道如果确定了直线的位置,那么将直线两边的点分别求和再乘起来就是答案

    那么现在只需要枚举直线的位置即可,只有当直线扫过点的时候值才会发生变化,所以我们离散化地取枚举每个节点,在跨过节点的时候只需要 O(1) 的复杂度就能对答案进行更新。

  • 代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<stack>
using namespace std;
#define  LL long long int
const double pi=4*atan(1.0);
const int  MAXN=50009;
int T;
int n;
LL sum_up,sum_down;
struct Node
{
    int x,y,v;
    double r;
    bool is_up;//1表示在x轴上面
}node[MAXN];
double Get_r(int x,int y)//给定一个点的坐标,如果这个点在x轴上方,返回这个点和原点连线与轴正方向的夹角。如果这个点在x轴下方,返回这个点和原点连线与轴负方向的夹角
{
    if(x==0)return pi;
    if(y==0)return 0;
    if(x<0 && y>0)return pi-atan(-(double)y/(double)x);
    if(x>0 && y<0)return pi-atan(-(double)y/(double)x);
    return atan((double)y/(double)x);
}
bool Get_up(int x,int y)//判断一个节点在x轴上方还是下方,在x轴上的点正方向归为下方,负方向归为上方
{
    if(y>0)return 1;
    else if(y<0)return 0;
    else
    {
        if(x<0)return 1;
        else return 0;
    }
}
bool cmp(Node a,Node b)
{
    return a.r < b.r;
}
void In()
{
    sum_up=sum_down=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
         scanf("%d%d%d",&node[i].x,&node[i].y,&node[i].v);
         if(node[i].x==0 && node[i].y==0)node[i].v=0;
         node[i].r=Get_r(node[i].x,node[i].y);
         node[i].is_up=Get_up(node[i].x,node[i].y);
         if(node[i].is_up==1)sum_up+=node[i].v;
         else sum_down+=node[i].v;
    }
}
LL Work()
{
    LL ans=sum_up*sum_down;
    double cur_r=0;
    int i=1;
    while(node[i].r==0)i++;
    while(i<=n)
    {
        cur_r=node[i].r;
        while(node[i].r==cur_r)
        {
            if(node[i].is_up==1)
            {
                sum_up-=node[i].v;
                sum_down+=node[i].v;
            }
            else
            {
                sum_up+=node[i].v;
                sum_down-=node[i].v;
            }
            i++;
        }
        ans=max(ans,sum_down*sum_up);
    }
    return ans;
}
void Test()
{
    cout<<"sum_up="<<sum_up<<",sum_down="<<sum_down<<endl;
    for(int i=1;i<=n;i++)cout<<node[i].is_up<<" ";
    cout<<endl;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        In();
        //Test();
        sort(node+1,node+n+1,cmp);
        cout<<Work()<<endl;
    }
}
/*
2
2
1 1 1
1 -1 1
3
1 1 1
1 -1 10
-1 0 100

1
4
1 0 4
0 1 5
0 -1 3
-2 0 6

*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值