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 }

 

posted @ 2016-07-03 19:56  GFY  阅读(195)  评论(0编辑  收藏  举报