Luogu-3222 [HNOI2012]射箭
阿新 • • 發佈:2018-11-24
幾何題,二次函式,化一下式子吧
設二次函式\(y=ax^2+bx\),對於一個線段\((x,y1)\),\((x,y2)\),與他相交的條件是\(y1<=ax^2+bx<=y2\)
對於\(ax^2+bx>=y1\),可以化為變數為\(a,b\)的一次函式\(b>=xa+\frac{y1}{x}\),這可以表示成(a-b)平面上的一個半平面...
如果一些線段的半平面交不為空,就說明存在一條拋物線可以經過他們
二分答案判斷,時間複雜度\(O(nlogn)\)
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=2e5+100; struct Point{ double x,y; Point(double xx=0,double yy=0){ x=xx,y=yy; } }; struct Vector{ double x,y; Vector(double xx=0,double yy=0){ x=xx,y=yy; } }; struct Line{ Point p; Vector v; double ang; int bh; Line(Point a=Point(),Vector b=Vector()){ p=a,v=b; ang=atan2(v.y,v.x); } }q[maxn],b[maxn],c[maxn]; int dcmp(double x){return fabs(x)<1e-17?0:(x>0?1:-1);} Vector operator - (Point a,Point b){return Vector(a.x-b.x,a.y-b.y);} Point operator + (Point a,Vector b){return Point(a.x+b.x,a.y+b.y);} Vector operator * (double p,Vector a){return Vector(a.x*p,a.y*p);} double operator * (Vector a,Vector b){return a.x*b.y-a.y*b.x;} double operator * (Point a,Point b){return a.x*b.y-a.y*b.x;} bool operator < (Line x,Line y){return dcmp(x.ang-y.ang)==0?(dcmp(x.v*(y.p-x.p))>0):(x.ang<y.ang);} Point glt(Line x,Line y){Vector v=x.p-y.p; return x.p+y.v*v/(x.v*y.v)*x.v;} bool onright(Line a,Line b,Line t){Point p=glt(a,b); return dcmp(t.v*(p-t.p))<0;} bool bpm(int x,int n,Line *b){ int l=0,r=1,tot=0; for(int i=1;i<=n;i++) if(b[i].bh<=x){ if(b[i].ang!=b[i-1].ang) tot++; c[tot]=b[i]; } n=tot,q[0]=c[1],q[1]=c[2]; for(int i=3;i<=n;i++){ while(l<r&&onright(q[r],q[r-1],c[i])) r--; while(l<r&&onright(q[l],q[l+1],c[i])) l++; q[++r]=c[i]; } while(l<r&&onright(q[r],q[r-1],q[l])) r--; while(l<r&&onright(q[l],q[l+1],q[r])) l++; return r-l>=2; } int n,m; double x,sy,ty; int main(){ scanf("%d",&m); for(int i=1;i<=m;i++){ scanf("%lf%lf%lf",&x,&sy,&ty); b[++n]=Line(Point(0,sy/x),Vector(1,-x)); b[n].bh=i; b[++n]=Line(Point(0,ty/x),Vector(-1,x)); b[n].bh=i; } sort(b+1,b+n+1); int l=1,r=n+1,mid,ans; while(l<r){ mid=l+r>>1; if(bpm(mid,n,b)) ans=mid,l=mid+1; else r=mid; } printf("%d\n",ans); return 0; }