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

    题目

    wdnmd这精度卡死我了

    不难发现答案是存在单调性的,于是我们二分就好了;现在要做的就是给定一些竖直线段,问是否存在一条标准抛物线经过所有线段

    对于一条线段((x_i,l_i,r_i)),如果(f(x)=ax^2+bx)经过它的话需要满足(l_ileq ax_i^2+bx_ileq r_i)

    也就是说(ax_i^2+bx_i-l_igeq 0,ax_i^2+bx_i-r_ileq 0)

    这里的(x_i,l_i,r_i)都是常数啊,于是我们考虑把(a,b)看成平面上的点,于是这又变成了直线的解析式了,我们还是半平面交即可。

    注意到这是一条标准的抛物线,于是需要满足(a<0,b>0),于是我们在加两条直线将((a,b))限制在第二象限内就好了

    提前排好序,二分的时候直接用就能做到(O(nlog n))的复杂度了

    之后大力卡卡精度就过了

    代码

    #include<bits/stdc++.h>
    #define re register
    #define double long double
    const double eps=1e-15;
    const double inf=1e18;
    const int maxn=1e5+5;
    int n,N,h,t,cnt,tot;
    struct pt{double x,y;};
    struct Line{pt s,t;double det;int id;}q[maxn<<1],L[maxn<<1],d[maxn<<1];
    inline int dcmp(double a,double b) {return a+eps>b&&a-eps<b;}
    const pt operator^(double t,const pt &A) {return (pt){t*A.x,t*A.y};}
    inline double operator*(const pt &A,const pt &B) {return A.x*B.y-A.y*B.x;}
    inline pt operator+(const pt &A,const pt &B) {return (pt){A.x+B.x,A.y+B.y};}
    inline pt operator-(const pt &A,const pt &B) {return (pt){A.x-B.x,A.y-B.y};}
    inline int OnRight(const pt &c,const Line &A) {return (A.t-c)*(A.s-c)>0;}
    inline pt sec(const Line &A,const Line &B) {
    	pt v1=A.t-A.s,v2=B.t-B.s,v3=A.s-B.s;
    	double t=(v3*v2)/(v2*v1);
    	return A.s+(t^v1);
    }
    inline int cmp(const Line &A,const Line &B) {
    	return dcmp(A.det,B.det)?OnRight(A.s,B):(A.det<B.det);
    }
    inline int half(int mid) {
    	cnt=0,tot=1;h=1,t=0;
    	for(re int i=1;i<=N;i++)if(L[i].id<=mid)d[++cnt]=L[i];
    	for(re int i=2;i<=cnt;i++) {
    		if(!dcmp(d[i-1].det,d[i].det)) ++tot;
    		d[tot]=d[i];
    	}
     	for(re int i=1;i<=tot;i++) {
    		while(h<t&&OnRight(sec(q[t],q[t-1]),d[i])) --t;
    		while(h<t&&OnRight(sec(q[h],q[h+1]),d[i])) ++h;
    		q[++t]=d[i];
    	}
    	while(h<t&&OnRight(sec(q[t],q[t-1]),q[h])) --t;
    	while(h<t&&OnRight(sec(q[h],q[h+1]),q[t])) ++h;
    	return (t-h>1);
    }
    int main() {
    	scanf("%d",&n);double c,sq,l,r;
    	for(re int i=1;i<=n;i++) {
    		scanf("%Lf%Lf%Lf",&c,&l,&r);sq=c*c;
    		L[++N].id=i;L[N].s=(pt){-1,(l+sq)/c},L[N].t=(pt){1,(l-sq)/c};
    		L[++N].id=i;L[N].s=(pt){1,(r-sq)/c};L[N].t=(pt){-1,(r+sq)/c};
    	}
    	L[++N].s=(pt){-eps,eps},L[N].t=(pt){-eps,inf};
    	L[++N].s=(pt){-inf,eps},L[N].t=(pt){-eps,eps};
    	for(re int i=1;i<=N;i++)L[i].det=atan2((L[i].t-L[i].s).y,(L[i].t-L[i].s).x);
    	std::sort(L+1,L+N+1,cmp);
    	int L=1,R=n,nw=0;
    	while(L<=R) {
    		int mid=L+R>>1;
    		if(half(mid)) L=mid+1,nw=mid;else R=mid-1;
    	}
    	printf("%d
    ",nw);return 0;
    }
    
  • 相关阅读:
    23丨当Postgres磁盘读引起IO高的时候,应该怎么办
    22丨案例:当磁盘参数导致IO高的时候,应该怎么办
    LNMP环境搭建
    virtualbox中centos虚拟机网络配置
    chrome扩展程序开发
    Linux账号管理
    Linux设置文件与Shell操作环境
    Yii2之组件的注册与创建
    Stream 源码分析
    Exchanger 源码分析
  • 原文地址:https://www.cnblogs.com/asuldb/p/12165543.html
Copyright © 2011-2022 走看看