hdu6127 Hard challenge

Hard challenge

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



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个点以及每个点的val,这些点两两之间连成线段 ,线段的权值为两个点的val相乘(前提这些线段都不经过原点)现在让你经过原点做一条直线然后求与这个直线相交的线段权值的和最大。

解题思路:先将所有的点与原点相连的直线的斜率求出来,然后对它们进行排序(从小到大),图中的绿线就是经过原点的那个直线依次扫过图中箭头所指的四个部分(注意当绿线L与L1重合此时经过a1点不算与a1a2,a1a3,a1a4相交)没经过一个部分算一下当前权值和,每次取大的。这里算权值和的时候有一个技巧:我们令s1为x>=0时的权值和,s2为小于0时的。然后每在一个区域如果x>0,就令s1减去该点的权值s2加上该点的权值,如果x<0令s1加上s2减去。令s1,s2相乘就是所经过的权值和。
已上图为例,开始时初始化s1*s2=(a1+a2)*(a3+a4)先经过a1,x>0,变为a2*(a3+a4+a1)=a2a3+a1a2+a2a4正好为其经过的线段,以后的计算也按此计算,既不重复也不遗漏。这也是观察出来的。
AC代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 1e9
using namespace std;
typedef long long LL;
const int maxn=50005;
int T,n,s1,s2;
LL ans;
struct node
{
	int x,y,val;
	double k;
}t[maxn];
bool cmp(node a,node b)
{
	return a.k<b.k;
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		s1=0;
		s2=0;
		ans=0;
		scanf("%d",&n);
		for(int i=0;i<n;i++)
		{
			scanf("%d%d%d",&t[i].x,&t[i].y,&t[i].val);
			if(t[i].x>=0)
			{
				s1+=t[i].val;
			}
			else
			{
				s2+=t[i].val;
			}
			if(t[i].x==0)
			{
				t[i].k=(t[i].y>0?inf:-inf);
			}
			else
			{
				t[i].k=(double)t[i].y/(double)t[i].x;
			}
		}
		ans=s1*s2;
		sort(t,t+n,cmp);
		for(int i=0;i<n;i++)
		{
			if(t[i].x>=0)
			{
				s1-=t[i].val;
				s2+=t[i].val;
			}
			else
			{
				s1+=t[i].val;
				s2-=t[i].val;
			}
			ans=max(ans,(LL)s1*s2);
		}
		printf("%lld\n",ans);
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值