bzoj2732[HNOI2012]射箭
题意:给出n条y轴右侧的和y轴平行的线段,问用一条经过(0,0)开口向下且对称轴在y轴右侧的抛物线最多能贯穿多少条编号从1开始依次递增的线段.
分析:首先有单调性,考虑二分答案转化为判定问题,那么记抛物线为y=ax^2+bx(a<0,b>0),每个线段对应两个关于a和b的二元一次不等式,也就是两个半平面,我们对当前需要打穿的靶子找出半平面,用半平面交求出(a,b)的可行域判断是否非空即可.因为a<0,b>0所以还要加包围框.
然后…这数据好强….我WA了17次,好像不是最多的…最后面向数据debug了一波
1.可行域可以是一个点或一个线段,这时也是有解的.我把靶子向上下各延长一点,这样点和线段就变成了多边形
2.使用long double
3.eps需要不断的尝试,不同的代码可能需要不同的eps,我最后是1e-18过的
4.ax^2+bx必须满足a<0,b>0,需要在包围框中体现这个限制
5.a,b不能等于0,所以包围框的坐标不能放在0,需要把包围框稍微移动一点,比如从0挪到-1e-13
WA17次.....好像还不是最多的...
要了数据...一个是原数据,一个是加强的一些边界数据
https://files.cnblogs.com/files/liu-runda/%E5%8A%A0%E5%BC%BA%E7%9A%84%E6%95%B0%E6%8D%AE.zip
https://files.cnblogs.com/files/liu-runda/%E9%83%A8%E5%88%86%E5%8E%9F%E6%95%B0%E6%8D%AE.rar
#include<cstdio> #include<cmath> #include<algorithm> using namespace std; const long double eps=1e-18; int cmp(long double x){return x<-eps?-1:x>eps;} const int maxn=300000; struct point{ long double x,y; point(){} point(long double a,long double b){x=a;y=b;} }p[maxn]; point operator +(const point &A,const point &B){return point(A.x+B.x,A.y+B.y);} point operator -(const point &A,const point &B){return point(A.x-B.x,A.y-B.y);} long double cross(const point &A,const point &B){return A.x*B.y-A.y*B.x;} struct line{ point s,d;long double arg;line(){} line(point S,point D){s=S;d=D;arg=atan2(d.y,d.x);} bool operator <(const line &B)const{ return cmp(arg-B.arg)==-1; } }L[maxn],q[maxn]; long double x[maxn],Y1[maxn],Y2[maxn]; int n,head,tail; point mult(long double t,point A){return point(A.x*t,A.y*t);} point intersect(line A,line B){ long double t=cross(B.d,A.s-B.s)/cross(A.d,B.d); return A.s+mult(t,A.d); } bool toleft(line A,point B){ return cmp(cross(A.d,B-A.s))>0; } bool HPI(){ sort(L,L+n); head=tail=0;q[tail++]=L[0]; for(int i=1;i<n;++i){ while(head+1<tail&&!toleft(L[i],p[tail-2]))tail--; while(head+1<tail&&!toleft(L[i],p[head])) head++; q[tail++]=L[i]; if(head+1<tail&&cmp(cross(q[tail-1].d,q[tail-2].d))==0){ tail--; if(toleft(q[tail-1],L[i].s))q[tail-1]=L[i]; } if(head+1<tail)p[tail-2]=intersect(q[tail-1],q[tail-2]); } while(head+1<tail&&!toleft(q[head],p[tail-2]))tail--; p[tail-1]=intersect(q[head],q[tail-1]); /* bool flag=true; for(int i=head;i<tail;++i){ if(cmp(p[i].x)!=0)flag=false; } if(flag)return false;*///printf("!"); return tail-head>=3; } bool check(int ans){ n=0; L[n++]=line(point(0,0),point(1e15,0));L[n++]=line(point(-1e-13,0),point(0,1e15)); L[n++]=line(point(0,1e15),point(-1e15,0));L[n++]=line(point(-1e15,0),point(0,-1e15));//cha long double a,b,c1,c2; for(int i=1;i<=ans;++i){ a=x[i]*x[i];b=x[i];c1=Y1[i];c2=Y2[i]; L[n++]=line(point(0,c2/b),point(-1e3,1e3*a/b));L[n++]=line(point(0,c1/b),point(1e3,-1e3*a/b)); } // for(int i=0;i<n;++i)printf("(%f,%f)+(%f,%f)\n",double(L[i].s.x),double(L[i].s.y),double(L[i].d.x),double(L[i].d.y)); return HPI(); } int main(){ int n;scanf("%d",&n); int a,b,c; for(int i=1;i<=n;++i){ scanf("%d%d%d",&a,&b,&c);x[i]=a;Y1[i]=b;Y2[i]=c;Y1[i]-=eps;Y2[i]+=eps; } int l=1,r=n; while(l<=r){ int mid=(l+r)>>1; if(check(mid))l=mid+1; else r=mid-1; } printf("%d\n",l-1); return 0; }