[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;
}
posted @ 2017-01-03 19:37  Aireen_Ye  阅读(176)  评论(0编辑  收藏  举报
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.