题目大意:
多组测试数据(t<=5),每组给你平面直角坐标系上的 n 个(1<=n<=5e4)。这n个点两两之间有一条连线,连线值为这两点的值的乘积。现在让你选一条过原点的直线,使得经过直线的线段的值的和最大。
分析:
直线绕原点旋转,尺取每个点和原点的连线和 x 轴正方向的夹角(0~2π)。即:尺取每个点进入直线上区域或下区域。
未AC代码:
#include<bits/stdc++.h>
#define maxn 50050
using namespace std;
int n;
double small=1e-7;
double p=4*atan(1.0);
struct point
{
int x;int y;
double ang;
long long int v;
}a[maxn];
double Get_ang(int x,int y)
{
double t=(double)(y)/(double)(x);
if(x>0&&y>0)return atan(t);
if(x<0&&y>0)return p-atan(-t);
if(x<0&&y<0)return p+atan(t);
if(x>0&&y<0)return 2*p-atan(-t);
if(y==0)
{
if(x>0)return 0;
else return p;
}
if(x==0)
{
if(y>0)return p/2;
else return 3*p/2;
}
}
bool cmp(point a,point b)
{
return a.ang<b.ang;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
long long int up=0,down=0,temp_v;
int num=0,temp_x,temp_y;
for(int i=0;i<n;i++)
{
scanf("%d%d%lld",&temp_x,&temp_y,&temp_v);
if(temp_x==0&&temp_y==0)continue;
a[num].x=temp_x;
a[num].y=temp_y;
a[num].v=temp_v;
a[num].ang=Get_ang(a[num].x,a[num].y);
if(a[num].y>0||(a[num].y==0&&a[num].x>0))//x轴正方向上得点在up,x轴负方向上的点在down。
{
up+=a[i].v;
}
else
{
down+=a[i].v;
}
num++;
}
//printf("%lld %lld\n",up,down);
sort(a,a+num,cmp);
long long int ans=down*up;
n=num;
int j=0;
for(int i=0;i<n;i++)
{
if(a[i].ang>p-small)
{
j=i;
break;
}
}
int i=0;
while(1)//每次循环计算第i个在下面,第j个在上面的值
{
if(i>=n||abs(a[i].ang-p)<small)break;
up-=a[i].v;down+=a[i].v;
while(1)
{
if(i>=n||a[i+1].ang-a[i].ang>small)break;
i++;
up-=a[i].v;down+=a[i].v;
}
while(1)
{
if(j>=n||a[j].ang>a[i].ang+p+small)break;
up+=a[j].v;down-=a[j].v;
j++;
}
j--;
ans=max(ans,up*down);
}
while(1)//每次循环计算第i个在下面,第j个在上面的值.2
{
if(i>=n)break;
up-=a[i].v;down+=a[i].v;
while(1)
{
if(i>=n||a[i+1].ang-a[i].ang>small)break;
i++;
up-=a[i].v;down+=a[i].v;
}
if(i>=n)i=n-1;
j=max(j,i+1);
while(1)
{
if(j>=n||a[j].ang>a[i].ang-p+small&&j<i)break;
up+=a[j].v;down-=a[j].v;
j++;
j%=n;
}
j--;
ans=max(ans,up*down);
}
/* for(int i=0;i<n-1;i++)
{
up-=a[i].v;
down+=a[i].v;
if(a[i+1].ang>p-small)
{
j%=n;
while(1)
{
if(a[j].ang>a[i+1].ang-p-small)break;
up+=a[j].v;
down-=a[j].v;
j++;
j%=n;
}
}
else while(1)
{
if(a[j].ang>p+a[i+1].ang-small)break;
up+=a[j].v;
down-=a[j].v;
j++;
j%=n;
}
printf("%lld %lld\n",up,down);
ans=max(ans,up*down);
//printf("%lld",ans);
}*/
printf("%lld\n",ans);
}
}
边界问题。