[HNOI2012]射箭
题意:
依次给出垂直于x轴的n条线段,求第几次给出的线段及其之前的所有线段不能被一条过原点开口朝下的抛物线穿过
Solution
Part1:限制条件与转化
显然,求解第几条线段不能被抛物线穿过,可以运用二分答案。
接下来就只要考虑如何check当前的线段都能不能被穿过
若设该抛物线为: \(y=Ax^2+Bx+C\)
而已知的 \(cnt\) 条线段是从 \((x_i,highy_i)\) 到 \((x_i,lowy_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已略去):
这不恰好是求解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;
}