[bzoj2732][HNOI2012]射箭
Posted Aireen Ye
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj2732][HNOI2012]射箭相关的知识,希望对你有一定的参考价值。
Description
沫沫最近在玩一个二维的射箭游戏,如下图所示,这个游戏中的$x$轴在地面,第一象限中有一些竖直线段作为靶子,任意两个靶子都没有公共部分,也不会接触坐标轴。沫沫控制一个位于$(0,0)$的弓箭手,可以朝$0$至$90$°中的任意角度(不包括$0$°$,90$°),以任意大小的力量射出带有穿透能力的光之箭。由于游戏中没有空气阻力,并且光之箭没有箭身,箭的轨迹会是一条标准的抛物线,被轨迹穿过的所有靶子都认为被沫沫射中了,包括那些只有端点被射中的靶子。这个游戏有多种模式,其中沫沫最喜欢的是闯关模式。在闯关模式中,第一关只有一个靶子,射中这个靶子即可进入第二关,这时在第一关的基础上会出现另外一个靶子,若能够一箭双雕射中这两个靶子便可进入第三关,这时会出现第三个靶子。依此类推,每过一关都会新出现一个靶子,在第$K$关必须一箭射中前$K$关出现的所有K个靶子才能进入第$K+1$关,否则游戏结束。沫沫花了很多时间在这个游戏上,却最多只能玩到第七关“七星连珠”,这让她非常困惑。于是她设法获得了每一关出现的靶子的位置,想让你告诉她,最多能通过多少关。
Input
第一行是一个正整数$N$,表示一共有$N$关。
接下来有$N$行,第$i+1$行是用空格隔开的三个正整数$x_i,y_{i,1},y_{i,2}(y_{i,1}<y_{i,2})$,表示第$i$关出现的靶子的横坐标是$x_i$,纵坐标的范围是从$y_{i,1}$到$y_{i,2}$。
Output
仅包含一个整数,表示最多的通关数。
Sample Input
5
2 8 12
5 4 5
3 8 10
6 2 3
1 3 7
Sample Output
3
HINT
$N\;\leq\;100000$,且给出的所有坐标不超过$10^9$。
Solution
二分$K$.
对于前$K$关,如果能过,则存在一条抛物线$y=ax^2+bx$,满足$y_{i,1}\;\leq\;ax_i^2+bx_i\;\leq\;y_{i,2}$,即关于$a,b$的不等式方程组$ax_i^2+bx_i-y_{i,1}\;\geq\;0,ax_i^2+bx_i-y_{i,2}\;\leq\;0$有解.
即求半平面交.
#include<cmath> #include<ctime> #include<queue> #include<stack> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 200010 #define eps 1e-13 #define INF 1e15 using namespace std; typedef long double ld; struct point{ ld x,y; }p[N]; struct line{ point s,e;int n;ld an; }l[N],a[N],q[N]; int n,m,h,t,lef,rig,mid,cnt; inline int read(){ int ret=0;char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)){ ret=(ret<<1)+(ret<<3)+c-‘0‘; c=getchar(); } return ret; } inline ld rd(){ int ret=0;char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)){ ret=(ret<<1)+(ret<<3)+c-‘0‘; c=getchar(); } return (ld)(ret); } inline ld sqr(ld x){ return x*x; } inline point add(point x,point y){ return (point){x.x+y.x,x.y+y.y}; } inline point dec(point x,point y){ return (point){x.x-y.x,x.y-y.y}; } inline point mul(point x,point y){ return (point){x.x*y.x,x.y*y.y}; } inline point div(point x,point y){ return (point){x.x/y.x,x.y/y.y}; } inline ld mult(point x,point y){ return x.x*y.y-x.y*y.x; } inline bool cmp(line x,line y){ if(x.an==y.an) return mult(dec(x.e,x.s),dec(y.s,x.s))>0; return x.an<y.an; } inline point inter(line a,line b){ ld s1,s2,t;point ret; s1=mult(dec(b.e,a.s),dec(a.e,a.s)); s2=mult(dec(a.e,a.s),dec(b.s,a.s)); t=s2/(s1+s2); ret.x=b.s.x+(b.e.x-b.s.x)*t; ret.y=b.s.y+(b.e.y-b.s.y)*t; return ret; } inline bool chk(line x,line y,line z){ point a=inter(x,y); return mult(dec(a,z.s),dec(z.e,z.s))>0; } inline bool hpi(int k){ cnt=0; for(int i=1;i<=m;++i) if(l[i].n<=k){ if(!cnt||l[i].an!=a[cnt].an) ++cnt; a[cnt]=l[i]; } h=1;t=0; for(int i=1;i<=cnt;++i){ while(h<t&&chk(q[t],q[t-1],a[i])) --t; while(h<t&&chk(q[h],q[h+1],a[i])) ++h; q[++t]=a[i]; } while(h<t&&chk(q[t],q[t-1],q[h])) --t; while(h<t&&chk(q[h],q[h+1],q[t])) ++h; return t-h+1>=3; } /*a^2x+ay-b=0,ask y*/ inline ld f(ld a,ld b,ld x){ return b/a-a*x; } inline void Aireen(){ n=read();ld x,y,z; l[++m].s=(point){-INF,-INF};l[m].e=(point){INF,-INF}; l[m].an=atan2(l[m].e.y-l[m].s.y,l[m].e.x-l[m].s.x); l[++m].s=(point){INF,-INF};l[m].e=(point){INF,INF}; l[m].an=atan2(l[m].e.y-l[m].s.y,l[m].e.x-l[m].s.x); l[++m].s=(point){INF,INF};l[m].e=(point){-INF,INF}; l[m].an=atan2(l[m].e.y-l[m].s.y,l[m].e.x-l[m].s.x); l[++m].s=(point){-INF,INF};l[m].e=(point){-INF,-INF}; l[m].an=atan2(l[m].e.y-l[m].s.y,l[m].e.x-l[m].s.x); for(int i=1;i<=n;++i){ x=rd();y=rd();z=rd(); l[++m].s.x=-1.0;l[m].s.y=f(x,y,l[m].s.x); l[m].e.x=1.0;l[m].e.y=f(x,y,l[m].e.x); l[m].n=i;l[m].an=atan2(l[m].e.y-l[m].s.y,l[m].e.x-l[m].s.x); l[++m].s.x=1.0;l[m].s.y=f(x,z,l[m].s.x); l[m].e.x=-1.0;l[m].e.y=f(x,z,l[m].e.x); l[m].n=i;l[m].an=atan2(l[m].e.y-l[m].s.y,l[m].e.x-l[m].s.x); } sort(l+1,l+1+m,cmp); lef=0;rig=n; while(lef<rig){ mid=lef+rig+1>>1; if(hpi(mid)) lef=mid; else rig=mid-1; } printf("%d\n",lef); } int main(){ freopen("archery.in","r",stdin); freopen("archery.out","w",stdout); Aireen(); fclose(stdin); fclose(stdout); return 0; }
以上是关于[bzoj2732][HNOI2012]射箭的主要内容,如果未能解决你的问题,请参考以下文章