=== ===
这里放传送门
=== ===
题解
这题很容易想到按照解析式 y=ax2+bx 和给定的纵坐标范围列出方程然后求半平面交看看有没有交集,也就是会列出一些 yi,1≤ax2i+bxi≤yi,2 这样的东西来,其中 xi 和 yi 都是已知量。因为这个题数据范围比较大所以需要用 O(nlogn) 的半平面交,那么就不能支持在线算法,需要提前知道所有要用的半平面,所以又加入了二分,二分当前能打到哪一关就可以了。
然后就是炸精度,炸精度,炸精度。。。。一开始在直线选点的时候选了和坐标轴的焦点,但这样的话万一遇到过原点的直线就不好办了。然后就是eps不能选的太大,因为当坐标很大的时候做除法会把数字除到1e-9那个级别去。最后加了long double才过掉。。
代码
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const long double eps=1e-16;
const long double inf=1e11;
const long double P=-1.0;
const long double Q=4.0;
int n,N,head,tail;
long double X[200010],Y[200010],Yy[200010];
struct Vector{
long double x,y;
Vector(long double X=0,long double Y=0){x=X;y=Y;}
Vector operator + (const Vector &a){return Vector(x+a.x,y+a.y);}
Vector operator - (const Vector &a){return Vector(x-a.x,y-a.y);}
long double operator * (const Vector &a){return x*a.y-y*a.x;}
Vector mul(long double t){return Vector(x*t,y*t);}
}poly[200010],p[200010];
struct Line{
Vector P,v;
long double ang;
Line(){P=Vector();v=Vector();}
Line(Vector A,Vector B){
P=A;v=B-A;ang=atan2(v.y,v.x);
}
}L[200010],q[200010];
int comp(Line a,Line b){return a.ang<b.ang;}
Vector GLI(Line A,Line B){
Vector u=A.P-B.P;
long double t=(B.v*u)/(A.v*B.v);
return A.P+A.v.mul(t);
}
bool Onleft(Line A,Vector w){return A.v*(w-A.P)>-eps;}
bool HalfpIns(){
sort(L+1,L+N+1,comp);
head=tail=1;q[1]=L[1];
for (int i=2;i<=N;i++){
while (head<tail&&!Onleft(L[i],p[tail-1])) --tail;
while (head<tail&&!Onleft(L[i],p[head])) ++head;
q[++tail]=L[i];
if (fabs(q[tail].v*q[tail-1].v)<eps){
--tail;
if (Onleft(q[tail],L[i].P))
q[tail]=L[i];
}
if (head<tail) p[tail-1]=GLI(q[tail],q[tail-1]);
}
while (head<tail&&!Onleft(q[head],p[tail-1])) --tail;
if (tail-head<=1) return false;
return true;
}
bool check(int mid){
Vector A,B,v;N=0;
long double x,y,yy,M1,M2;
for (int i=1;i<=mid;i++){
x=X[i];y=Y[i];yy=Yy[i];
y-=eps;yy+=eps;
B=Vector(P,(yy-x*x*P)/x);
A=Vector(Q,(yy-x*x*Q)/x);
L[++N]=Line(A,B);
A=Vector(P,(y-x*x*P)/x);
B=Vector(Q,(y-x*x*Q)/x);
L[++N]=Line(A,B);
}
L[++N]=Line(Vector(eps,inf),Vector(-inf,inf));
L[++N]=Line(Vector(-inf,inf),Vector(-inf,eps));
L[++N]=Line(Vector(-inf,eps),Vector(eps,eps));
L[++N]=Line(Vector(eps,eps),Vector(eps,inf));
return HalfpIns();
}
inline int getnum() {
int ans = 0; char c; bool flag = false;
while ((c = getchar()) == ' ' || c == '\n' || c == '\r');
if (c == '-') flag = true; else ans = c - '0';
while ((c = getchar()) >= '0' && c <= '9') ans = ans * 10 + c - '0';
return ans * (flag ? -1 : 1);
}
int Divide(int l,int r){
int mid,ans=0;
while (l<=r){
mid=(l+r)>>1;
if (check(mid)){ans=max(ans,mid);l=mid+1;}
else r=mid-1;
}
return ans;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++){
X[i]=getnum();Y[i]=getnum();Yy[i]=getnum();
}
printf("%d\n",Divide(1,n));
return 0;
}
偏偏在最后出现的补充说明
背板子,背板子,背板子T_T