采用的做法是 AtCoder 上的官方题解思路。
实际上,eps 设为 [10−13,10−12] 的时候才是 WA On #91,而 eps 设为 [10−20,10−14] 的时候又成了 WA 在另外的 4 个点(#91 AC 了),所以猜测可能是因为某个细节没有特判导致的?
这个题已经做了一个上午了,差一点就能 AC,实在是不想就这么放弃
#include<iostream>
#include<algorithm>
using namespace std;
#define double long double
// #define DEBUG
inline int read(){
int ret=0;
char ch=' ',c=getchar();
while(!('0'<=c&&c<='9')) ch=c,c=getchar();
while('0'<=c&&c<='9') ret=ret*10+(c^48),c=getchar();
return ch=='-'?-ret:ret;
}
const double INF=0x3f3f3f3f3f3f3f3f;
const double eps=(double)(1e-4)*(double)(1e-4)*(double)(1e-5)*(double)(1e-5);
inline bool _less(double x,double y){ return y-x>eps; }
inline bool _great(double x,double y){ return x-y>eps; }
inline bool _le(double x,double y){ return !_great(x,y); }
inline bool _ge(double x,double y){ return !_less(x,y); }
inline bool _equal(double x,double y){ return _le(x,y)&&_ge(x,y); }
struct pdd{
double first,second;
pdd(){}
pdd(double x,double y){ first=x,second=y; }
friend bool operator< (pdd &a,pdd &b){
if(!_equal(a.first,b.first)) return _less(a.first,b.first);
return _less(a.second,b.second);
}
friend bool operator== (pdd &a,pdd &b){
if(!_equal(a.first,b.first)) return false;
if(!_equal(a.second,b.second)) return false;
return true;
}
friend bool operator> (pdd &a,pdd &b){
if(!_equal(a.first,b.first)) return _great(a.first,b.first);
return _great(a.second,b.second);
}
};
// 各种重载
inline bool is_counter_clockwise(pdd &vec_a,pdd &vec_b){
return _less(vec_a.first*vec_b.second,vec_b.first*vec_a.second);
}
// 判断向量 b 是否在向量 a 的逆时针方向
inline bool not_convex_hull(pdd &s,pdd &t,pdd &x){
pdd vec_a=pdd(x.first-s.first,x.second-s.second);
pdd vec_b=pdd(x.first-t.first,x.second-t.second);
return is_counter_clockwise(vec_a,vec_b);
}
// Andrew 算法判凸壳
inline pdd get_line(pdd &a,pdd &b){
if(_equal(a.first,b.first)) return pdd(INF,a.first);
double K=(b.second-a.second)/(b.first-a.first);
double B=a.second-K*a.first;
return pdd(K,B);
}
// 获取直线方程
inline pdd get_cross(pdd &a,pdd &b,double K){
pdd line=get_line(a,b);
if(_ge(line.first,INF)){
double Y=K*line.second;
return pdd(line.second,Y);
}
if(_equal(line.first,K)){
if(_equal(line.second,0.00)) return a;
return pdd(INF,INF);
}
double X=line.second/(K-line.first);
double Y=line.first*X+line.second;
return pdd(X,Y);
}
// 获取直线与查询(相当于一条 y=kx 的直线)直线的交点
inline bool is_cross(pdd &a,pdd &b,double K){
#ifdef DEBUG
printf("crossing (%.2Lf,%.2Lf)->(%.2Lf,%.2Lf) with y=%.2Lf*x",a.first,a.second,b.first,b.second,K);
#endif
pdd cross_pt=get_cross(a,b,K);
double L=a.first,R=b.first;
return (_le(L,cross_pt.first)&&_le(cross_pt.first,R));
}
// 判断是否相交在线段上
int n,Q;
const int N=4e5+10;
pdd pos[N];
int _stk[N<<1],tt=0;
inline void push(int x){
#ifdef DEBUG
printf("push(%d)\n",x);
#endif
_stk[++tt]=x;
}
inline void pop(){
#ifdef DEBUG
printf("pop(%d)\n",_stk[tt]);
#endif
tt--;
}
#define stk(x) pos[_stk[x]]
void andrew(int bg){
tt=0;
push(bg),push(bg+1);
for(int i=bg+2;i<=n;i++){
while(tt>=2&¬_convex_hull(stk(tt-1),stk(tt),pos[i])) pop();
push(i);
}
/*
push(n-1);
int hh=tt;
for(int i=n-2;i>=1;i--){
while(tt>=hh&¬_convex_hull(stk(tt-1),stk(tt),pos[i])) tt--;
push(i);
}
*/
// 这里只用求下凸包
}
int main(){
double mi_k=INF;
int mi_id=0;
double ma_x=0,ma_y=0;
n=read();
double x,y;
for(int i=1;i<=n;i++){
x=read(),y=read();
pos[i]=pdd(y,x);
if(_less(ma_x,y)){
ma_x=y;
ma_y=x;
}
else if(_equal(ma_x,y)){
if(_great(ma_y,x)) ma_y=x;
}
}
// 更新时间最优点
sort(pos+1,pos+1+n);
n=unique(pos+1,pos+1+n)-(pos+1);
for(int i=1;i<=n;i++){
y=pos[i].first,x=pos[i].second;
if(_great(mi_k,x/y)){
mi_k=x/y;
mi_id=i;
}
}
// 更新效率最优点(耗能最少)
if(mi_id==n){
double sta=pos[n].second/pos[n].first;
Q=read();
while(Q--){
x=read(),y=read();
if(_less(x/y,sta)) puts("-1");
else printf("%.16Lf\n",y/pos[n].first);
}
return 0;
}
// 特判只有一个点的情况
andrew(mi_id);
/*
if(mi_id+1==n){
if(pos[1]>pos[2]) swap(pos[1],pos[2]);
Q=read();
while(Q--){
x=read(),y=read();
if(x/y<mi_k){
puts("-1");
continue;
}
if(x/y>=(ma_y/ma_x)){
printf("%.10Lf\n",y/ma_x);
continue;
}
pdd cross_pt=get_cross(pos[1],pos[2],x/y);
printf("%.10Lf\n",y/cross_pt.first);
}
return 0;
}
*/
#ifdef DEBUG
for(int i=1;i<=tt;i++) printf("%d ",_stk[i]);
printf("\n");
#endif
Q=read();
while(Q--){
x=read(),y=read();
double K=x/y;
if(_less(K,mi_k)){
puts("-1");
continue;
}
if(_ge(K,ma_y/ma_x)){
printf("%.16Lf\n",y/ma_x);
continue;
}
int l=2,r=tt,mid;
while(l<r){
mid=(l+r)>>1;
if(is_cross(stk(1),stk(mid),K)) r=mid;
else l=mid+1;
}
#ifdef DEBUG
printf("=== l=%d\n",l);
#endif
pdd cross_pt=get_cross(stk(l-1),stk(l),K);
printf("%.16Lf\n",y/cross_pt.first);
}
return 0;
}