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


    此题重点在卡精度!!!

    本地已经下载数据测试并通过了,然而$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); 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 }
  • 相关阅读:
    【NOIP2018】游记
    题解 P1441 【砝码称重】
    题解 P3128 【[USACO15DEC]最大流Max Flow】
    题解 P1949 【聪明的打字员_NOI导刊2011提高(10)】
    题解 P1966 【火柴排队】
    题解 P1895 【数字序列】
    topcoder做题
    1149E
    hdu 6589
    hdu 6579
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10355684.html
Copyright © 2020-2023  润新知