【极角排序+双指针线性扫】2017多校训练七 HDU 6127 Hard challenge
acm.hdu.edu.cn/showproblem.php?pid=6127
【题意】
- 给定平面直角坐标系中的n个点,这n个点每个点都有一个点权
- 这n个点两两可以连乘一条线段,定义每条线段的权值为线段两端点点权的乘积
- 现在要过原点作一条直线,要求这条直线不经过任意一个给定的点
- 在所有n个点两两连成的线段中,计算与这条直线有交点的线段的权值和
- 最大化这个权值和并输出
- 题目保证,给定的n个点不重合且任意两个点的连线不经过原点
【思路】
- 一条经过原点的直线把n个点分成两个半平面A,B
- 假设A中的点权分别为a1,a2....an;B中的点权分别为b1,b2,......bm。则结果为sumA*sumB
- 极角排序,枚举每个起点,线性扫一圈,计算半平面的点权之和,不断更新最优值
【AC】
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<cmath> 6 #include<algorithm> 7 8 using namespace std; 9 typedef long long ll; 10 const int maxn=5e4+2; 11 int n; 12 double xx[maxn]; 13 double yy[maxn]; 14 ll val[maxn]; 15 ll ans[maxn]; 16 17 double dis(double x1,double y1,double x2,double y2){return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));} 18 const double eps = 1e-6; 19 struct Point 20 { 21 double x; 22 double y; 23 ll val; 24 double dis; 25 double alf; 26 Point(){} 27 Point(double _x,double _y):x(_x),y(_y){} 28 Point(double _x,double _y,ll _val):x(_x),y(_y),val(_val){} 29 Point operator -(const Point &t) const 30 { 31 return Point(x-t.x,y-t.y); 32 } 33 double operator ^(const Point &t)const 34 { 35 return (x*t.y)-(y*t.x); 36 } 37 }p[maxn]; 38 Point o(0.0,0.0); 39 bool cmp(const Point &a, const Point &b)//先按象限排序,再按极角排序,再按远近排序 40 { 41 if (a.y == 0 && b.y == 0 && a.x*b.x <= 0)return a.x>b.x; 42 if (a.y == 0 && a.x >= 0 && b.y != 0)return true; 43 if (b.y == 0 && b.x >= 0 && a.y != 0)return false; 44 if (b.y*a.y <= 0)return a.y>b.y; 45 return ((a-o)^(b-o))> 0.0 || (((a-o)^(b-o)) == 0.0 && a.x < b.x); 46 } 47 48 int main() 49 { 50 int T; 51 scanf("%d",&T); 52 while(T--) 53 { 54 memset(ans,0,sizeof(ans)); 55 scanf("%d",&n); 56 ll sum=0; 57 for(int i=0;i<n;i++) 58 { 59 scanf("%lf%lf%I64d",&xx[i],&yy[i],&val[i]); 60 p[i]=Point(xx[i],yy[i],val[i]); 61 sum+=val[i]; 62 } 63 sort(p,p+n,cmp); 64 int l=1; 65 ll res; 66 ans[0]+=p[0].val; 67 for(int i=0;i<n;i++) 68 { 69 if(i>0) ans[i]=ans[i-1]-p[i-1].val; 70 while(((p[i]-o)^(p[l]-o))>0) 71 { 72 ans[i]+=p[l].val; 73 l=(l+1)%n; 74 } 75 if(i==0) res=ans[i]*(sum-ans[i]); 76 else res=max(res,ans[i]*(sum-ans[i])); 77 } 78 printf("%I64d\n",res); 79 } 80 return 0; 81 }
【模板】
1 bool cmp(const Point &a, const Point &b)//先按象限排序,再按极角排序,再按远近排序 2 { 3 if (a.y == 0 && b.y == 0 && a.x*b.x <= 0)return a.x>b.x; 4 if (a.y == 0 && a.x >= 0 && b.y != 0)return true; 5 if (b.y == 0 && b.x >= 0 && a.y != 0)return false; 6 if (b.y*a.y <= 0)return a.y>b.y; 7 return ((a-o)^(b-o))> 0.0 || (((a-o)^(b-o)) == 0.0 && a.x < b.x); 8 }
1 int l=1; 2 ll res; 3 // ans[0]+=p[0].val; 4 for(int i=0;i<n;i++) 5 { 6 //if(i>0) ans[i]=ans[i-1]-p[i-1].val; 7 while(((p[i]-o)^(p[l]-o))>0) 8 { 9 // 必要的运算 10 l=(l+1)%n; 11 } 12 //这里更新答案 13 }