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

    XVII.[HNOI2012]射箭

    强烈谴责本道卡精度屑题。

    首先,乍一看,二次函数\(ax^2+b\)\(x=x_0\)处的值要在\([y_0,y_1]\)之内?带进去不就是一个关于\(a,b\)的半平面交吗?

    然后再一看,要找到半平面交非空的最大位置, 难不成要用动态凸包?

    后来想想动态凸包什么的完全没有必要啦,直接二分一下即可。

    同时,满足题意的凸包,必须有 \(a<0,b>0\),于是我们加入四条边界线即可。

    然后就开始疯狂debug了。

    下面扯一些我犯的蠢蠢的错误:

    1. 将向量和直线模板化过度,以至于某些本来没有意义的符号也变的有意义了。

    例:我定义了向量和向量间的&符号、直线和直线间的&符号、向量和直线间的&符号,然后就开始混用三个符号了……

    1. 滥用atan2函数。

    atan2函数还是有一定的常数的,滥用会使得程序常数过大。

    1. 使用了\(O(n\log^2n)\)的算法。

    应该在最外面就先把所有直线排好序,这样单次半平面交就是\(O(n)\)的了。

    同时,还需要一点点耐心,一点点long double和一点点1e-15的精度……

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define double long double
    const double eps=1e-15;
    const double inf=1e11;
    int cmp(double x){
    	if(x>eps)return 1;
    	if(x<-eps)return -1;
    	return 0;
    }
    struct Vector{
    	double x,y;
    	Vector(){}
    	Vector(double X,double Y){x=X,y=Y;}
    	friend Vector operator +(const Vector &u,const Vector &v){return Vector(u.x+v.x,u.y+v.y);}
    	friend Vector operator -(const Vector &u,const Vector &v){return Vector(u.x-v.x,u.y-v.y);}
    	friend Vector operator *(const Vector &u,const double &v){return Vector(u.x*v,u.y*v);}
    	friend double operator &(const Vector &u,const Vector &v){return u.x*v.y-u.y*v.x;}//cross times
    	double operator !()const{return atan2(y,x);}//the angle of a vector
    };
    typedef Vector Point;
    struct Line{
    	Point x;
    	Vector z;
    	double ag;
    	Line(){}
    	Line(Point X,Point Y){x=X,z=Y-X,ag=!z;}
    	friend bool operator <(const Line &u,const Line &v){return u.ag<v.ag;} 
    	friend bool operator ^(const Line &u,const Point &v){return cmp(u.z&(v-u.x))==-1;}
    	friend Point operator &(const Line &u,const Line &v){
    		return u.x+u.z*((v.z&(u.x-v.x))/(u.z&v.z));
    	}
    }l[200100],a[200100];
    Point p[200100];
    int L,R,ord[200100],n,m;
    typedef Line Segment;
    bool Semiplane_Intersection(int lim){
    	int i=1;
    	while(ord[i]>lim)i++;
    	l[L=R=1]=a[ord[i]];
    	for(i++;i<=m;i++){
    		if(ord[i]>lim)continue;
    		while(L<R&&a[ord[i]]^p[R-1])R--;
    		while(L<R&&a[ord[i]]^p[L])L++;
    		if(a[ord[i]].ag!=l[R].ag)l[++R]=a[ord[i]];
    		else if(a[ord[i]]^l[R].x)l[R]=a[ord[i]];
    		if(L<R)p[R-1]=l[R]&l[R-1];
    	}
    	while(L<R&&l[L]^p[R-1])R--;
    	return R-L>1;
    }
    int read(){
    	int x=0;
    	char c=getchar();
    	while(c>'9'||c<'0')c=getchar();
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    	return x;
    }
    int main(){
    	n=read();
    	a[1]=Line(Point(-inf,eps),Point(-eps,eps));
    	a[2]=Line(Point(-eps,eps),Point(-eps,inf));
    	a[3]=Line(Point(-eps,inf),Point(-inf,inf));
    	a[4]=Line(Point(-inf,inf),Point(-inf,eps));
    	for(int i=1;i<=n;i++){
    		double x=read(),y=read(),z=read();
    		a[2*i+3]=Line(Point(0,y/x),Point(1,y/x-x));
    		a[2*i+4]=Line(Point(1,z/x-x),Point(0,z/x));
    	}
    	m=2*n+4;
    	for(int i=1;i<=m;i++)ord[i]=i;
    	sort(ord+1,ord+m+1,[](int u,int v){return a[u]<a[v];});
    //	for(int i=1;i<=2*n+4;i++)a[i].x.print(),a[i].y.print(),puts("");
    	int l=0,r=n;
    	while(l<r){
    		int mid=(l+r+1)>>1;
    		if(Semiplane_Intersection(2*mid+4))l=mid;
    		else r=mid-1;
    	}
    	printf("%d\n",l);
    	return 0;
    }
    

  • 相关阅读:
    ----uni-app之解决底部按钮绝对定位后被软键盘推起的bug----
    ----uni-app之解决app手机键盘消失后页面往上滚的问题----
    mysql tips
    mysql 添加行号
    mysql中的几种join 及 full join问题
    Dcoker中启动mysql,并实现root远程访问
    DockerToolbox在Win7上的安装和设置
    Class.getResourceAsStream 和 ClassLoder.getResourceAsStream 的区别
    tomcat 启动异常 EOFException: Unexpected end of ZLIB input stream
    java异常处理-finally中使用return和throw语句
  • 原文地址:https://www.cnblogs.com/Troverld/p/14619369.html