• [HNOI2012]射箭


    题目描述

    沫沫最近在玩一个二维的射箭游戏,如下图 1 所示,这个游戏中的 x 轴在地面,第一象限中有一些竖直线段作为靶子,任意两个靶子都没有公共部分,也不会接触坐标轴。

    沫沫控制一个位于(0,0)的弓箭手,可以朝 0 至 90?中的任意角度(不包括 0度和 90度),以任意大小的力量射出带有穿透能力的光之箭。由于游戏中没有空气阻力,并且光之箭没有箭身,箭的轨迹会是一条标准的抛物线,被轨迹穿过的所有靶子都认为被沫沫射中了,包括那些 只有端点被射中的靶子。

    这个游戏有多种模式,其中沫沫最喜欢的是闯关模式。

    在闯关模式中,第一关只有一个靶 子,射中这个靶子即可进入第二关,这时在第一关的基础上会出现另外一个靶子,若能够一箭 双雕射中这两个靶子便可进入第三关,这时会出现第三个靶子。依此类推,每过一关都会新出 现一个靶子,在第 K 关必须一箭射中前 K 关出现的所有 K 个靶子才能进入第 K+1 关,否则游戏 结束。

    沫沫花了很多时间在这个游戏上,却最多只能玩到第七关”七星连珠“,这让她非常困惑。 于是她设法获得了每一关出现的靶子的位置,想让你告诉她,最多能通过多少关

    输入输出格式

    输入格式:

    输入文件第一行是一个正整数N,表示一共有N关。接下来有N行,第i+1行是用空格隔开的三个正整数xi,yi1,yi2(yi1<yi2 ),表示第i关出现的靶子的横坐标是xi,纵坐标的范围是从yi1到yi2 。 输入保证30%的数据满足N<=100,50%的数据满足N<=5000,100%的数据满足N<=100000且给 出的所有坐标不超过109 。

    输出格式:

    仅包含一个整数,表示最多的通关数。

    输入输出样例

    输入样例#1:

    5
    2 8 12
    5 4 5
    3 8 10
    6 2 3
    1 3 7

    输出样例#1:

    3


    题解

    对于每个限制((x1,y1),(x2,y2))需要满足
    (ax1^2+bx1>=y1\ax2^2+bx2<=y2)
    然后可以看做是(ax1+b>=frac{y1}{x1}\ax2+b<=frac{y2}{x2})
    移一下项(b>=frac{y1}{x1}-ax1\b<=frac{y2}{x2}-ax2)
    然后就可以把每个限制想成两条直线,把(b)作为坐标轴
    做半平面交即可

    代码

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    # define double long double
    const int M = 300050 ;
    const double INF = 1e18 ;
    const double EPS = 1e-19 ;
    using namespace std ;
    
    inline int read() {
        char c = getchar() ; int x = 0 , w = 1 ;
        while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
        while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
        return x*w ;
    }
    
    int n , cnt ;
    inline int sgn(double x) {
        if(fabs(x) < EPS) return 0 ;
        return x > 0 ? 1 : -1 ;
    }
    struct Vec {
        double x , y ;
        Vec (double Tx = 0 , double Ty = 0) {
            x = Tx , y = Ty ;
        }
    } p[M] ;
    
    inline Vec operator + (Vec A , Vec B) {
        return (Vec) { A.x + B.x , A.y + B.y } ;
    }
    inline Vec operator - (Vec A , Vec B) {
        return (Vec) { A.x - B.x , A.y - B.y } ;
    }
    inline Vec operator * (Vec A , double B) {
        return (Vec) { A.x * B , A.y * B } ;
    }
    inline Vec operator / (Vec A , double B) {
        return (Vec) { A.x / B , A.y / B } ;
    }
    
    struct Line {
        int id ;
        Vec s , t , v ; double Ang ;
        Line () { } ;
        Line (int idt , Vec A , Vec B) {
            id = idt ; s = A ; t = B ; 
            v = t - s ; Ang = atan2(v.y , v.x) ;
        }
    } l[M] , que[M] ;
    
    inline double Dot(Vec A , Vec B) {
        return A.x * B.x + A.y * B.y ;
    }
    inline double Cross(Vec A , Vec B) {
        return A.x * B.y - A.y * B.x ;
    }
    inline bool operator < (Line A , Line B) {
        if(sgn(A.Ang - B.Ang) != 0) return A.Ang < B.Ang ;
        else return sgn(Cross(A.v , B.s - A.s)) < 0 ; 
    }
    inline bool Is_para(Line A , Line B) {
        return sgn(Cross(A.v , B.v)) == 0 ;
    }
    inline bool OnRight(Vec P , Line L) {
        return sgn(Cross(P - L.s , L.v)) > 0 ;
    }
    inline Vec GLI(Line A , Line B) {
        Vec c = B.s - A.s ;
        double t = Cross(B.v , c) / Cross(B.v , A.v) ;
        return A.s + A.v * t ;
    }
    
    inline bool check(int mid) {
        int i = 1 , head = 1 , tail = 1 ;
        while(l[i].id > mid) 
            ++ i ;
        que[tail] = l[i] ;
        for(++ i ; i <= cnt ; i ++) {
            if(l[i].id > mid) continue ;
            if(head < tail && (Is_para(que[head] , que[head + 1]) || Is_para(que[tail - 1] , que[tail])))
                return false ;
            while(head < tail && OnRight(p[tail - 1] , l[i])) -- tail ;
            while(head < tail && OnRight(p[head] , l[i])) ++ head ;
            if(sgn(que[tail].Ang - l[i].Ang)) que[++tail] = l[i] ;
            else continue ;
            if(head < tail) p[tail - 1] = GLI(que[tail] , que[tail - 1]) ;
        }
        while(head < tail && OnRight(p[tail - 1] , que[head])) -- tail ;
        while(head < tail && OnRight(p[head] , que[tail])) ++ head ;
        if(tail - head <= 1) return false ;
        return true ;
    }
    int main() {
        n = read() ;
        for(int i = 1 , x , yf , ys ; i <= n ; i ++) {
            x = read() ; yf = read() ; ys = read() ;
            Vec p1 = Vec (0.0 , (double)yf / x) ; Vec p2 = Vec (1.0 , (double)yf / x - x) ;
            Vec p3 = Vec (1.0 , (double)ys / x - x) ; Vec p4 = Vec (0.0 , (double)ys / x) ;
            l[++cnt] = Line ( i , p1 , p2 ) ; l[++cnt] = Line ( i , p3 , p4 ) ;
        }
        l[++cnt] = Line ( 0 , Vec(-INF , EPS) , Vec(-EPS , EPS) ) ;
        l[++cnt] = Line ( 0 , Vec(-EPS , EPS) , Vec(-EPS , INF) ) ;
        l[++cnt] = Line ( 0 , Vec(-EPS , INF) , Vec(-INF , INF) ) ;
        l[++cnt] = Line ( 0 , Vec(-INF , INF) , Vec(-INF , EPS) ) ;
        sort(l + 1 , l + cnt + 1) ;
        int l = 1 , r = n , ret = 0 ;
        while(l <= r) {
            int mid = (l + r) >> 1 ;
            if(check(mid)) l = mid + 1 , ret = mid ;
            else r = mid - 1 ;
        }
        printf("%d
    ",ret) ;
        return 0 ;
    }
    
  • 相关阅读:
    其实你的痛苦 跟别人完全没有关系
    一篇很好的“金刚念诵要诀” 首愚法师开示【精华】 [唇齿不动]的过程及要诀
    无我的智慧十五
    随在你:放心的智慧
    利用念头及情绪
    [转载]无我的智慧 第一章 镜中修行
    看到自己真实本性的人
    肯.威尔伯论觉知
    觉醒之光【六】觉醒
    觉醒之光【十一】关系
  • 原文地址:https://www.cnblogs.com/beretty/p/10513209.html
Copyright © 2020-2023  润新知