1. 程式人生 > >【BZOJ2732】【HNOI2012】射箭 二分+半平面交

【BZOJ2732】【HNOI2012】射箭 二分+半平面交

while a* 卡精度 con $2 bsp 二分 can end

此題重點在卡精度!!!

本地已經下載數據測試並通過了,然而$B$站上還是$WA$的,可能是$CPU$對於$long\ double$ 的資瓷不一樣。

此題答案顯然是可以二分出來的,設當前要監測是否能射穿前$mid$個靶子。

我們發現要穿過第i個靶子,那麽$a,b$必須滿足$l_i≤ax_i^2+bx_i≤r_i$。

我們簡單地轉化下式子,我們就可以得到$\dfrac{l_i}{x_i^2}+\dfrac{b}{x_i}≤a≤\dfrac{r_i}{x_i^2}+\dfrac{b}{x_i}$。

我們想象一個以$b$為橫坐標,$a$為縱坐標的平面直角坐標系中,這一對約束可以通過兩個半平面的交來表示。

不難發現滿足射穿前$mid$個靶子的數對$(a,b)$,必然在這$2mid$個半平面的交內。

於是問題就轉化為這2$mid$個半平面是否有交(半平面交判定)

時間復雜度:$O(n\ \log\ n)$。

 1 #include<bits/stdc++.h>
 2 #define M 210005
 3 #define D long double
 4 #define eps 1e-20
 5 #define INF 1e15
 6 using namespace std;
 7 
 8 int dx[M]={0},dl[M]={0},dr[M]={0},m=0;
 9 
10
struct pt{ 11 D x,y; pt(D X=0,D Y=0){x=X; y=Y;} 12 friend pt operator +(pt a,pt b){return pt(a.x+b.x,a.y+b.y);} 13 friend pt operator -(pt a,pt b){return pt(a.x-b.x,a.y-b.y);} 14 friend D operator *(pt a,pt b){return a.x*b.y-a.y*b.x;} 15 void out(){printf("(%.1Lf,%.1Lf)",x,y);}
16 }; 17 struct line{ 18 pt a,b; D ang; int id; 19 line(){a=pt(0,0); b=pt(0,0);} 20 line(pt A,pt B,int ID){ id=ID; a=A; b=B; 21 ang=atan2(b.y-a.y,b.x-a.x);} 22 23 D getk(){return (b.y-a.y)/(b.x-a.x);} 24 D getb(){return a.y-a.x*getk();} 25 friend bool operator <(line a,line b){return a.ang<b.ang;} 26 friend pt operator *(line a,line b){ 27 D k1=(b.b-a.a)*(a.b-a.a); 28 D k2=(a.b-a.a)*(b.a-a.a); 29 D t=k2/(k1+k2); 30 return pt(b.a.x+t*(b.b.x-b.a.x),b.a.y+t*(b.b.y-b.a.y)); 31 } 32 }p[M],q[M]; 33 bool inleft(line a,line b,line c){ 34 pt d=a*b; 35 return (d-c.a)*(c.b-c.a)<=eps; 36 } 37 bool solve(int n){ 38 int l=1,r=0; 39 for(int i=1;i<=m;i++){ 40 if(p[i].id>n) continue; 41 while(l<r&&(!inleft(q[r-1],q[r],p[i]))) r--; 42 while(l<r&&(!inleft(q[l+1],q[l],p[i]))) l++; 43 q[++r]=p[i]; 44 } 45 while(l<r&&(!inleft(q[r-1],q[r],q[l]))) r--; 46 while(l<r&&(!inleft(q[l+1],q[l],q[r]))) l++; 47 return r-l>=2; 48 } 49 int main(){ 50 int n;scanf("%d",&n); if(n<=3){printf("%d\n",n); return 0;} 51 for(int i=1;i<=n;i++) scanf("%d%d%d",dx+i,dl+i,dr+i); 52 int l=1,r=n; 53 for(int i=1;i<=n;i++){ 54 D L=dl[i],R=dr[i],X=dx[i]; 55 p[++m]=line(pt(0,L/(X*X)),pt(1,L/(X*X)-1/X),i); 56 p[++m]=line(pt(1,R/(X*X)-1/X),pt(0,R/(X*X)),i); 57 } 58 pt a1=pt(INF,INF),a2=pt(-INF,INF),a3=pt(-INF,-INF),a4=pt(INF,-INF); 59 p[++m]=line(a1,a2,0); p[++m]=line(a2,a3,0); p[++m]=line(a3,a4,0); p[++m]=line(a4,a1,0); 60 sort(p+1,p+m+1); 61 while(l<r){ 62 int mid=(l+r+1)>>1; 63 if(solve(mid)) l=mid; 64 else r=mid-1; 65 } 66 cout<<l<<endl; 67 }

【BZOJ2732】【HNOI2012】射箭 二分+半平面交