题意:
给T组数据,每组数据有一个n,代表n个点,接下来n行,每行给出一个x和y还有val,代表每个点的位置和值。两个点连起来的值等于两点的val相乘,不存在两点同时存在于一条与原点相连的线上。问从原点处划一条直线,不与这n个点相交(即点都不能存在于这条直线上),能经过最大的边和是多少。
题解:
实际上,用直线分开两边,得到的和就是等于该线的上方的权值和乘以该线的下方的权值和。
先对这n个点进行极角排序,然后将他们分开4个象限,保存所有点的权值和,根据象限,也保存该象限的前缀和,方便后面的计算。
然后开始从第一象限的点开始扫描到第四象限,每扫描到一个点,同象限在其前面(包括它自身)的权值加起来,用双指针,在其旋转180度的象限中找到一个斜率比该点要大的点,将其与该象限剩下的点的权值加起来,还有将其顺时针90度的象限的所有点的权值也加起来,因为这些地方都是在该线的左侧。
然后枚举出来的该线的答案就是等于 当前的权值*(sum-当前的权值)。将所有点按象限都扫一次,就可以得到最大值了。
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const int N=5e4+5;
ll sum[5][N];
vector<int>vc[5];
int nx[]={0,4,1,2,3};
int fan[]={0,3,4,1,2};
struct point
{
int x,y,val;
point (int xx=0,int yy=0,int v=0):x(xx),y(yy),val(v){}
}p[N];
ll cross(const point &p1,const point &p2,const point &q1,const point &q2)
{
return (ll)(q2.y-q1.y)*(p2.x-p1.x)-(ll)(q2.x-q1.x)*(p2.y-p1.y);
}
bool cmp(const point &a,const point &b)
{
if (!a.y && !b.y && (ll)a.x*b.x<=0)
return a.x>b.x;
if (!a.y && a.x>=0 && b.y)
return 1;
if (!b.y && b.x>=0 && a.y)
return 0;
if ((ll)b.y*a.y<=0)
return a.y>b.y;
point one;
one.y=one.x=0;
return cross(one,a,one,b)>0 || (!cross(one,a,one,b) && a.x<b.x);
}
bool check(const point &a,const point &b)
{
point np(-a.x,-a.y);
return !cmp(np,b);
}
void push(int id,int i,int val)
{
vc[id].push_back(i);
sum[id][vc[id].size()]=sum[id][vc[id].size()-1]+val;
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
int n;
scanf("%d",&n);
for (int i=0 ; i<n ; ++i)
scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].val);
sort(p,p+n,cmp);
for (int i=0 ; i<=4 ; ++i)
{
vc[i].clear();
for (int j=0 ; j<=n ; ++j)
sum[i][j]=0;
}
ll s=0;
for (int i=0 ; i<n ; ++i)
{
if (p[i].x>=0 && p[i].y>=0)
push(1,i,p[i].val);
else if (p[i].x<0 && p[i].y>=0)
push(2,i,p[i].val);
else if (p[i].x<0 && p[i].y<0)
push(3,i,p[i].val);
else
push(4,i,p[i].val);
s+=p[i].val;
}
ll mx=0;
for (int i=1 ; i<=4 ; ++i)
{
if (!vc[i].size())
continue;
for (int j=0,k=0 ; j<vc[i].size() ; ++j)
{
ll tmp=sum[nx[i]][vc[nx[i]].size()]+sum[i][j+1];
while (k<vc[fan[i]].size() && check(p[vc[i][j]],p[vc[fan[i]][k]]))
++k;
tmp+=sum[fan[i]][vc[fan[i]].size()]-sum[fan[i]][k];
mx=max(tmp*(s-tmp),mx);
}
}
printf("%lld\n",mx);
}
return 0;
}
/*
10
4
-5 2 100
-2 -3 100
100000000 1000000000 10
100000000 999999999 9
2
1 1 1
1 -1 1
3
1 1 1
1 -1 10
-1 0 100
4
2 1 10
-4 -1 20
-3 -4 30
-2 -5 40
3
-1 2 10
3 -1 20
1 -5 30
*/