zoukankan      html  css  js  c++  java
  • [HNOI2012]射箭

    [HNOI2012]射箭

    题意:

    依次给出垂直于x轴的n条线段,求第几次给出的线段及其之前的所有线段不能被一条过原点开口朝下的抛物线穿过

    Solution

    Part1:限制条件与转化

    显然,求解第几条线段不能被抛物线穿过,可以运用二分答案。
    接下来就只要考虑如何check当前的线段都能不能被穿过
    若设该抛物线为: \(y=Ax^2+Bx+C\)
    而已知的 \(cnt\) 条线段是从 \((x_i,highy_i)\)\((x_i,lowy_i)\)
    应此可以得到:

    \[lowy_i\leq Ax_i^2+Bx_i+C\leq highy_i \]

    转化得:

    \[\frac{lowy_i}{x_i}\leq Ax_i+B+C\leq \frac{highy_i}{x_i} \]

    再转化一下,就能得到好看的两个不等式:

    \[Ax_i+B+C-\frac{lowy_i}{x_i}\geq 0 \]

    \[Ax_i+B+C-\frac{highy_i}{x_i}\leq 0 \]

    n条直线就转化成了\(2*n\)个不等式的约束
    现在问题就成了判断满足这\(2*n\)条约束的情况下有没有解,即:(A,B,C)有解
    对于C,因为抛物线过原点,因此\(C=0\)
    对于 A、B, \(A>0,B<0\)
    因此若是将(A,B)转化到坐标系上,必在第二象限

    Part2: 求解

    计算几何初步这篇文章中提到过,半平面交一种主要运用就是求解二元一次不等式组的解
    上式中(C=0已略去):

    \[Ax_i+B-\frac{lowy_i}{x_i}\geq 0 \]

    \[Ax_i+B-\frac{highy_i}{x_i}\leq 0 \]

    这不恰好是求解A,B吗
    当然还要加一个第二象限的大框框
    (为了保证半平面交是封闭图形,INF处也要加上约束)

    最后按照前文提到的方法求解即可

    Code

    挺难卡精度的,我加了特判才过luogu数据,darkbzoj倒是能直接过

    #include<bits/stdc++.h>
    using namespace std;
    #define re register
    #define int long long
    #define get getchar()
    #define in inline
    #define db double
    in int read()
    {
        int t=0, x=1; char ch=get;
        while(ch!='-' && (ch<'0' || ch>'9')) ch=get;
        if(ch=='-') ch=get, x=-1;
        while(ch<='9' && ch>='0') t=t*10+ch-'0', ch=get;
        return t*x;
    }
    const int _=4e5+23;
    const int inf=2e15;
    const db eps=1e-15;
    struct vec{
        db x,y;
        vec(){x=y=0;}
        vec(db a,db b){x=a, y=b;}
        vec operator +(const vec b)const {return vec(x+b.x, y+b.y);}
        vec operator -(const vec b)const {return vec(x-b.x, y-b.y);}
        vec operator ^(const db b)const {return vec(x*b,y*b);}
        db operator &(const vec b)const {return x*b.x+y*b.y;}
        db operator *(const vec b)const {return x*b.y-y*b.x;}
        db dis(){ return sqrt(x*x+y*y);}
    }a[_];
    struct line{
        vec st, ed;int id;vec c;
        bool operator <(const line l)const {
            db A=atan2(c.y,c.x), B=atan2(l.c.y,l.c.x);
            if(fabs(A-B)>eps) return A<B;
            return c*(l.ed-st)+eps<0;
        }
    }l[_], qwe[_], q[_];
    vec intersection(line l1,line l2)
    {
        vec st1=l1.st, st2=l2.st;
        vec a=l1.c, b=l2.c, c=st2-st1;
        if(fabs(b*a)<eps) return vec(-1e12,-1e12);
        return st1+(a^((b*c)/(b*a)));
    }
    int n, m, hd, tl;
    bool check(line a,line b,line c)
    {
        vec p=intersection(b,c);
        return (a.c*(p-a.st))+eps<0;
    }
    in int solve(int cnt,int lim)
    {
        int tot=0; tl=0, hd=1;
        for(re int i=1;i<=cnt;++i)
        {
            if(l[i].id>lim) continue;
            if(i>1 && fabs(atan2(l[i].c.y,l[i].c.x)-atan2(l[i-1].c.y, l[i-1].c.x))<eps) 
    	    continue;
            qwe[++tot]=l[i]; 
        }
        m=tot;
        for(re int i=1;i<=m;++i)
        {
            while(tl>hd && check(qwe[i], q[tl], q[tl-1])) tl--;
            while(tl>hd && check(qwe[i], q[hd], q[hd+1])) hd++;
            q[++tl]=qwe[i];
        }         
        while(tl>hd && check(q[hd], q[tl], q[tl-1])) tl--;
        while(tl>hd && check(q[tl], q[hd], q[hd+1])) hd++;
        return tl-hd+1>=3;
    }
    db X[_], hy[_], ly[_];
    in int check(int tot,int lim) {    return solve(tot,lim); }
    signed main()
    {
        n=read();
        for(re int i=1;i<=n;++i) X[i]=read(), ly[i]=read(), hy[i]=read();
        int tot=0;
        l[++tot]=(line){vec(-inf,eps),vec(-eps,eps),0};
        l[++tot]=(line){vec(-eps,eps),vec(-eps,inf),0};
        l[++tot]=(line){vec(-eps,inf),vec(-inf,inf),0};
        l[++tot]=(line){vec(-inf,inf),vec(-inf,eps),0};
        for(re int i=1;i<=n;++i)
        {
            l[++tot]=(line){vec(0,ly[i]/X[i]),vec(1,ly[i]/X[i]-X[i]),i};
            l[++tot]=(line){vec(1,hy[i]/X[i]-X[i]),vec(0,hy[i]/X[i]),i};
        }
        for(re int i=1;i<=tot;++i) l[i].c=l[i].ed-l[i].st;
        sort(l+1,l+tot+1);
        int l=1, r=n,ans=0;
        while(l<=r)
        {
            int mid=l+r>>1;
            if(check(tot,mid)) l=mid+1,ans=mid;
            else r=mid-1;
        }
        cout<<ans<<endl;
        return 0;
    }
    
    
    嗯,就这样了...
  • 相关阅读:
    SPOJ913 Query on a tree II
    SPOJ375 Query on a tree
    HDU4348 To the moon
    Bzoj2753 [SCOI2012]滑雪与时间胶囊
    HDU4612 Warm up
    Uva11374 Airport Express
    Uva1624 Knots
    DevExpress的GridControl的使用以及怎样添加列和绑定数据源
    C#中使用Path、Directory、Split、Substring实现对文件路径和文件名的常用操作实例
    ZedGraph的曲线的LineItem对象的Tag属性存储信息进而在鼠标悬浮时进行显示
  • 原文地址:https://www.cnblogs.com/yzhx/p/15760416.html
Copyright © 2011-2022 走看看