Hard challengeTime Limit: 4000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 1116 Accepted Submission(s): 460
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(1≤T≤5)
, denoting the number of test cases.
For each test case: The first line contains a positive integer n(1≤n≤5×104) . The next n lines, the i th line contains three integers xi,yi,vali(|xi|,|yi|≤109,1≤vali≤104) .
Output
For each test case:
A single line contains a nonnegative integer, denoting the answer.
Sample Input
Sample Output
|
题意 : 在平面直角坐标系上给出 n 个点,每个点带一个权值,两两点连线的权值为两个点权值的乘积,然后从原点发射一条直线(双向的)它获得的价值等于它穿过的直线段的价值的和。
要你求出最大值。
思路:题目有个重要条件,就是不会有两个点的连线经过原点,这个条件可以得出一个重要结论,就是你一定可以找到直线把所有的点分散在直线两边,形成两个点集,而不会出现两个点在直线上的情况,那么先把每个点计算出它的角度,然后按角度排个序,然后你只要对点给出一个判定条件(例如x坐标大于0)把点分成两部分,然后再依次把点放到另一个点集上,一边计算记录最大值就可以了。
计算的方法是先相加再相乘,如果一一对应相乘再相加的话,时间复杂度就超了。
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<math.h>
#include<string.h>
using namespace std;
#define maxn 50005
#define ll long long
#define PI 3.14159265
#define eps 1e-9
struct node{
double x,y,val,ang;
}p[maxn];
bool cmp(node a,node b){ //按照角度顺序排序
return a.ang < b.ang;
}
int main(){
ll t,n,x,y,val,ang;
ll tmp1,tmp2,ans;
scanf("%lld",&t);
while(t--){
scanf("%lld",&n);
memset(p,0,sizeof(p));
for(ll i = 1;i <= n;i++){
scanf("%lf %lf %lf",&p[i].x,&p[i].y,&p[i].val);
p[i].ang = atan(p[i].y / p[i].x); //根据tan值计算角度
}
sort(p + 1,p + 1 + n,cmp);
tmp1 = tmp2 = ans = 0;
for(int i = 1;i <= n;i++){ //以x坐标大于0和小于0分成两部分 分别加到tmp1 和 tmp2
if(p[i].x > eps)
tmp1 += p[i].val;
else
tmp2 += p[i].val;
}
ans = tmp1 * tmp2; // 两边的各个数相乘相加 = 相加 再 相乘
for(int i = 1;i <= n;i++){
if(p[i].x > 0){
tmp1 -= p[i].val; // 在右边的就放到左边去
tmp2 += p[i].val;
}else{
tmp1 += p[i].val; //在左边的就放到右边去
tmp2 -= p[i].val;
}
ans = max(ans,tmp1 * tmp2); //每次记录最大的
}
printf("%lld\n",ans);
}
return 0;
}