zoukankan      html  css  js  c++  java
  • bzoj 2732 射箭 半平面交

    2732: [HNOI2012]射箭

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 2531  Solved: 848
    [Submit][Status][Discuss]

    Description

    沫沫最近在玩一个二维的射箭游戏,如下图 1 所示,这个游戏中的 x 轴在地面,第一象限中有一些竖直线段作为靶子,任意两个靶子都没有公共部分,也不会接触坐标轴。沫沫控制一个位于(0,0)的弓箭手,可以朝 0 至 90?中的任意角度(不包括 0度和 90度),以任意大小的力量射出带有穿透能力的光之箭。由于游戏中没有空气阻力,并且光之箭没有箭身,箭的轨迹会是一条标准的抛物线,被轨迹穿过的所有靶子都认为被沫沫射中了,包括那些 只有端点被射中的靶子。这个游戏有多种模式,其中沫沫最喜欢的是闯关模式。在闯关模式中,第一关只有一个靶 子,射中这个靶子即可进入第二关,这时在第一关的基础上会出现另外一个靶子,若能够一箭 双雕射中这两个靶子便可进入第三关,这时会出现第三个靶子。依此类推,每过一关都会新出 现一个靶子,在第 K 关必须一箭射中前 K 关出现的所有 K 个靶子才能进入第 K+1 关,否则游戏 结束。沫沫花了很多时间在这个游戏上,却最多只能玩到第七关“七星连珠”,这让她非常困惑。 于是她设法获得了每一关出现的靶子的位置,想让你告诉她,最多能通过多少关

    Input

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

    这道题网上大部分题解都是错的,虽然有些可以A。

    要注意先用一个大矩形先把平面围住,这样就可以避免特殊情况。

    二分答案,发现是变成了形如ax^2+bx>y1,ax^1+bx<y2的不等式,把二次函数中的a和b当成x和y,求半平面交就行了。
      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<cmath>
      6 #define N 210000
      7 #define eps 1e-10
      8 #define inf 1e15
      9 using namespace std;
     10   
     11 int n;
     12   
     13 struct point
     14 {
     15     double x,y; 
     16     point(){};
     17     point(double _x,double _y)
     18     {
     19         x=_x;y=_y;
     20     }
     21 }p[N];
     22   
     23 point operator - (point a,point b)
     24 {
     25     return point(a.x-b.x,a.y-b.y);
     26 }
     27   
     28 point operator + (point a,point b)
     29 {
     30     return point(a.x+b.x,a.y+b.y);
     31 }
     32   
     33 point operator * (point a,double b)
     34 {
     35     return point(a.x*b,a.y*b);
     36 }
     37   
     38 point operator / (point a,double b)
     39 {
     40     return point(a.x/b,a.y/b);
     41 } 
     42   
     43 int dcmp(double x)//三态函数 
     44 {
     45     if(fabs(x)<eps)return 0;
     46     if(x>eps)return 1;
     47     return -1;
     48 }
     49   
     50 double cross(point a,point b)
     51 {
     52     return a.x*b.y-b.x*a.y;
     53 }
     54   
     55 struct line
     56 {
     57     point p,v;
     58     int id;
     59     double ang;
     60     line(){};
     61     line(point pp,point vv,int _id)
     62     {
     63         p=pp;v=vv;
     64         ang=atan2(v.y,v.x);
     65         id=_id;
     66     }
     67     friend bool operator < (line aa,line bb)
     68     {
     69         return aa.ang<bb.ang;
     70     }
     71 }lines[N],deq[N*2];
     72   
     73 point getpoint(line a,line b)
     74 {
     75     point u=a.p-b.p;
     76     double t=cross(b.v,u)/cross(a.v,b.v);
     77     return a.p+a.v*t;
     78 }
     79   
     80 bool onright(point a,line b)
     81 {
     82     return cross(b.v,a-b.p)<0;
     83 }
     84 int tot,h,t;
     85 void insert(line l)
     86 {
     87     while(h<t&&onright(p[t-1],l))t--;
     88     while(h<t&&onright(p[h],l))h++;
     89     deq[++t]=l;
     90     if(h<t&&dcmp(deq[t].ang-deq[t-1].ang)==0)t--;
     91     if(h<t)p[t-1]=getpoint(deq[t],deq[t-1]);
     92 }
     93   
     94 bool half(int cnt)
     95 {
     96     h=1;t=0;
     97     for(int i=1;i<=2*n+4;i++)
     98     {
     99         if(lines[i].id<=cnt)
    100         {
    101             insert(lines[i]);
    102         }
    103     }
    104     while(h<t&&onright(p[t-1],deq[h]))t--;
    105     return t-h>=2;
    106 }
    107   
    108 int main()
    109 {
    110     scanf("%d",&n);
    111     lines[++tot]=line(point(inf,inf),point(-1,0),0);
    112     lines[++tot]=line(point(-inf,inf),point(0,-1),0);
    113     lines[++tot]=line(point(-inf,-inf),point(1,0),0);
    114     lines[++tot]=line(point(inf,-inf),point(0,1),0);
    115     for(int i=1;i<=n;i++)
    116     {
    117         double x,y1,y2;
    118         scanf("%lf%lf%lf",&x,&y1,&y2);
    119         lines[++tot]=line(point(0,y1/x),point(1,-x),i);
    120         lines[++tot]=line(point(0,y2/x),point(-1,x),i);
    121     }
    122     sort(lines+1,lines+2*n+5);
    123     int ha=1,ta=n;
    124     while(ha<=ta)
    125     {
    126         int mid=(ha+ta)>>1;
    127         if(half(mid))
    128         {
    129             ha=mid+1;
    130         }
    131         else ta=mid-1;
    132     }
    133     printf("%d
    ",ta);
    134     return 0;
    135 }
    View Code
  • 相关阅读:
    【转】一步一步带你反编译apk,并教你修改smali和重新打包
    【转】安卓apk反编译、修改、重新打包、签名全过程
    【转】iOS安全之RSA加密/生成公钥、秘钥 pem文件
    Tomcat修改用户名密码教程
    docker安装使用教程(Kali2.0)
    WebSphere静默安装教程(WAS6.1为例)
    大学计算机书藉推荐(信息安全方向)
    计算机行业各种职业技能树
    APK骨架分析
    dvwa安装、配置、使用教程(Linux)
  • 原文地址:https://www.cnblogs.com/ezyzy/p/6296071.html
Copyright © 2011-2022 走看看