BZOJ 2732 射箭
http://www.lydsy.com/JudgeOnline/problem.php?id=2732
题意:给你n个靶子,让你求是否有一个经过原点的抛物线经过最多的前k个靶子,求出最大的k
思路:
就是这样的形式:y1<=ax^2+bx<=y2,这里y1,y2,x是已知的,有多组,我们发现,变量只有a和b了,而且都是一次,这样就转换成二元一次不等式组,这个问题就是高二学过的线性规划了
可以把它转换成半平面交,然后二分答案就可以了。
坑点:TM BZOJ上面要用longdouble,不然会WA一发,还有,考试的时候我居然在二分里面排序,导致复杂度退化到nlog^2 n T_T,这点要记住了。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define dou long double 7 const dou inf=1e15; 8 int tot,n; 9 struct Point{ 10 dou x,y; 11 Point(){} 12 Point(dou x0,dou y0):x(x0),y(y0){} 13 }; 14 struct Line{ 15 Point s,e; 16 dou slop; 17 int id; 18 Line(){} 19 Line(Point s0,Point e0):s(s0),e(e0){} 20 }l[200005],c[200005],L[200005]; 21 int read(){ 22 int t=0,f=1;char ch=getchar(); 23 while (ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();} 24 while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} 25 return t*f; 26 } 27 dou operator *(Point p1,Point p2){ 28 return p1.x*p2.y-p1.y*p2.x; 29 } 30 Point operator -(Point p1,Point p2){ 31 return Point(p1.x-p2.x,p1.y-p2.y); 32 } 33 bool cmp(Line p1,Line p2){ 34 if (p1.slop==p2.slop) return (p2.e-p1.s)*(p1.e-p1.s)>=0; 35 else return p1.slop<p2.slop; 36 } 37 Point inter(Line p1,Line p2){ 38 dou k1=(p2.e-p1.s)*(p1.e-p1.s); 39 dou k2=(p1.e-p1.s)*(p2.s-p1.s); 40 dou t=(k2)/(k1+k2); 41 dou x=p2.s.x+(p2.e.x-p2.s.x)*t; 42 dou y=p2.s.y+(p2.e.y-p2.s.y)*t; 43 return Point(x,y); 44 } 45 bool jud(Line p1,Line p2,Line p3){ 46 Point p=inter(p1,p2); 47 return (p-p3.s)*(p3.e-p3.s)>0; 48 } 49 bool check(int mid){ 50 int Tot=0; 51 for (int i=1;i<=tot;i++) 52 if (l[i].id<=mid) L[++Tot]=l[i]; 53 int cnt=1; 54 for (int i=2;i<=Tot;i++) 55 if (L[i].slop!=L[i-1].slop) L[++cnt]=L[i]; 56 int ll=1,rr=2; 57 c[1]=L[1];c[2]=L[2]; 58 for (int i=3;i<=Tot;i++){ 59 while (ll<rr&&jud(c[rr],c[rr-1],L[i])) rr--; 60 while (ll<rr&&jud(c[ll],c[ll+1],L[i])) ll++; 61 c[++rr]=L[i]; 62 } 63 while (ll<rr&&jud(c[rr],c[rr-1],c[ll])) rr--; 64 while (ll<rr&&jud(c[ll],c[ll+1],c[rr])) ll++; 65 if (rr-ll+1<3) return 0; 66 else return 1; 67 } 68 int main(){ 69 n=read(); 70 l[++tot].s=Point(-inf,inf);l[tot].e=Point(-inf,-inf); 71 l[++tot].s=Point(-inf,-inf);l[tot].e=Point(inf,-inf); 72 l[++tot].s=Point(inf,-inf);l[tot].e=Point(inf,inf); 73 l[++tot].s=Point(inf,inf);l[tot].e=Point(-inf,inf); 74 for (int i=1;i<=n;i++){ 75 dou x=read(),y1=read(),y2=read(); 76 l[++tot].s.x=-1;l[tot].s.y=y1/x-(-1)*x; 77 l[tot].e.x=1;l[tot].e.y=y1/x-x; 78 l[tot].id=i; 79 l[++tot].s.x=1;l[tot].s.y=y2/x-x; 80 l[tot].e.x=-1;l[tot].e.y=y2/x+x; 81 l[tot].id=i; 82 } 83 for (int i=1;i<=tot;i++) l[i].slop=atan2(l[i].e.y-l[i].s.y,l[i].e.x-l[i].s.x); 84 std::sort(l+1,l+1+tot,cmp); 85 int LL=1,RR=n,ans=0; 86 while (LL<=RR){ 87 int mid=(LL+RR)>>1; 88 if (check(mid)) ans=mid,LL=mid+1; 89 else RR=mid-1; 90 } 91 printf("%d",ans); 92 }