P3222 [HNOI2012]射箭

题意

考虑二分答案,我们只需要判断是否存在((a,b)),对于任意(iin[1,mid])满足(ax_i^2+bx_iin[y_{1i},y_{2i}])

展开可得:
(frac{y_{1i}}{x_i}leqslant ax_i+bleqslantfrac{y_{2i}}{x_i})
即:
(ax_i+b-frac{y_{1i}}{x_i}geqslant 0)
(ax_i+b-frac{y_{12}}{x_i}leqslant 0)

(a,b)当成(x,y),这是两条直线,我们半平面交判断即可。

然后这题卡精度卡了我一下午,我也是真有耐心。

code:

#include<bits/stdc++.h>
using namespace std;
#define double long double
const int maxn=100010;
const double eps=1e-18;
const double inf=1e12;
int n,m;
struct Point
{
    double x,y;
    inline double len(){return sqrt(x*x+y*y);}
    Point operator+(const Point a)const{return (Point){x+a.x,y+a.y};}
    Point operator-(const Point a)const{return (Point){x-a.x,y-a.y};}
    Point operator*(const double k){return (Point){x*k,y*k};}
    Point operator/(const double k){return (Point){x/k,y/k};}
    double operator*(const Point a)const{return x*a.y-y*a.x;}
    double operator&(const Point a)const{return x*a.x+y*a.y;}
};
inline int dcmp(double x)
{
    if(fabs(x)<=eps)return 0;
    return x<0?-1:1;
} 
inline Point get(Point a,Point b){return b-a;}
struct Line
{
    Point p,v;int id;double theta;
    bool operator<(const Line a)const
    {
        return !dcmp(theta-a.theta)?dcmp(get(p,v)*get(p,a.v))<0:dcmp(theta-a.theta)<0;
    } 
}line[maxn<<1],tmp[maxn<<1],q[maxn<<1];
inline Point getpoint(Line a,Line b)
{
    Point p1=a.p,p2=b.p,v1=a.v,v2=b.v;
    v1=get(p1,v1),v2=get(p2,v2);
    Point u=get(p1,p2);
    return p2+v2*(u*v1)/(v1*v2);
}
inline bool check(Line a,Line b,Line c)
{
    Point p=getpoint(a,b);
    return dcmp(get(c.p,c.v)*get(c.p,p))<0;
}
inline bool check_ans(int mid)
{
    int l=1,r=0,cnt=0;
    for(int i=1;i<=m;i++)
    	if(line[i].id<=mid&&line[i].theta!=tmp[cnt].theta)tmp[++cnt]=line[i];
    for(int i=1;i<=cnt;i++)
    {
        while(l<r&&check(q[r-1],q[r],tmp[i]))r--;
        while(l<r&&check(q[l],q[l+1],tmp[i]))l++;
        q[++r]=tmp[i];
    }
    while(l<r&&check(q[r-1],q[r],q[l]))r--;
    while(l<r&&check(q[l],q[l+1],q[r]))l++;
    return r-l+1>=3;
}
int main()
{
	//freopen("test.in","r",stdin);
	//freopen("test.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		double x,y1,y2;scanf("%Lf%Lf%Lf",&x,&y1,&y2);
		line[++m]=(Line){(Point){0,y1/x},(Point){1,y1/x-x},i,0};
		line[++m]=(Line){(Point){1,y2/x-x},(Point){0,y2/x},i,0};
	}
	line[++m]=(Line){(Point){-inf,eps},(Point){-eps,eps},0,0};
	line[++m]=(Line){(Point){-eps,eps},(Point){-eps,inf},0,0};
	line[++m]=(Line){(Point){-eps,inf},(Point){-inf,inf},0,0};
	line[++m]=(Line){(Point){-inf,inf},(Point){-inf,eps},0,0};
	for(int i=1;i<=m;i++)line[i].theta=atan2(line[i].v.y-line[i].p.y,line[i].v.x-line[i].p.x);
    sort(line+1,line+m+1);
	int l=1,r=n,res=0;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(check_ans(mid))res=mid,l=mid+1;
		else r=mid-1;
	}
	printf("%d
",res);
	return 0;
}
原文地址:https://www.cnblogs.com/nofind/p/12244720.html