P3222 [HNOI2012]射箭
题意
考虑二分答案,我们只需要判断是否存在\((a,b)\),对于任意\(i\in[1,mid]\)满足\(ax_i^2+bx_i\in[y_{1i},y_{2i}]\)。
展开可得:
\(\frac{y_{1i}}{x_i}\leqslant ax_i+b\leqslant\frac{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\n",res);
return 0;
}