显然当
c
>
0
c>0
c>0时,分数最大化的方案是将题目按照
p
i
t
i
\frac{p_i}{t_i}
tipi从大到小排序,
p
i
t
i
\frac{p_i}{t_i}
tipi相同的可以任意交换。那么我们容易算出第
i
i
i道题最早和最晚可能完成的时间
L
i
L_i
Li和
R
i
R_i
Ri。
考虑对于两道题目
i
i
i,
j
j
j(
p
i
<
p
j
p_i<p_j
pi<pj),合法的条件为
p
i
(
1
−
c
L
i
T
)
≤
p
j
(
1
−
c
R
i
T
)
p_i(1-\frac{cLi}{T})\leq p_j(1-\frac{cR_i}{T})
pi(1−TcLi)≤pj(1−TcRi),也即
p
j
R
j
−
p
i
L
i
p
j
−
p
i
≤
T
c
\frac{p_jR_j-p_iL_i}{p_j-p_i}\leq \frac{T}{c}
pj−pipjRj−piLi≤cT,于是我们需要算出所有限制中最大的一个。我们将所有题目按
p
i
p_i
pi排序后,限制是一个斜率的式子,对于题目
j
j
j,我们需要求出所有满足
p
i
<
p
j
p_i<p_j
pi<pj的
i
i
i中,点
(
p
i
,
p
i
L
i
)
(p_i,p_iL_i)
(pi,piLi)到
(
p
j
,
p
j
R
j
)
(p_j,p_jR_j)
(pj,pjRj)的最大斜率,这个在下凸壳上三分即可。因为我们已经按
p
i
p_i
pi排了序,横坐标单调,直接维护凸壳就行了。
时间复杂度
O
(
n
log
n
)
\mathcal O(n\log n)
O(nlogn)。
#include <bits/stdc++.h>
#define eps 1e-10
using namespace std;
typedef long double ldb;
typedef long long ll;
struct Point {
ll x,y;
Point() {}
Point(ll a,ll b):x(a),y(b) {}
Point operator - (Point b) {return Point(x-b.x,y-b.y);}
bool operator < (const Point & b) const {return (x*b.y!=y*b.x)?x*b.y<y*b.x:y<b.y;}
};
inline ldb cross(Point x,Point y) {
return (ldb)x.x*y.y-(ldb)x.y*y.x;
}
inline ldb rat(Point x,Point y) {
return (ldb)(x.y-y.y)/(x.x-y.x);
}
Point st[150005];
int top;
void insert(Point x) {
while (top>1&&cross(x-st[top],st[top]-st[top-1])>=0) top--;
st[++top]=x;
}
ldb query(Point x) {
int l=1,r=top;
while (r-l>2) {
int m1=l+(r-l)/3,m2=r-(r-l)/3;
if (rat(x,st[m1])>rat(x,st[m2])) r=m2; else l=m1;
}
ldb ans=0;
for(int i=l;i<=r;i++) ans=max(ans,rat(x,st[i]));
return ans;
}
Point p[150005];
ll lpos[150005],rpos[150005];
int id[150005];
bool cmp(int x,int y) {
return p[x].y<p[y].y;
}
int main() {
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&p[i].y);
for(int i=1;i<=n;i++) scanf("%lld",&p[i].x);
sort(p+1,p+n+1);
ll s=0;
for(int i=1;i<=n;i++) {
if (i>1&&p[i].x*p[i-1].y==p[i].y*p[i-1].x) lpos[i]=lpos[i-1];
else lpos[i]=s;
s+=p[i].x;
}
for(int i=1;i<=n;i++) lpos[i]+=p[i].x;
for(int i=n;i>0;i--) {
if (i<n&&p[i].x*p[i+1].y==p[i].y*p[i+1].x) rpos[i]=rpos[i+1];
else rpos[i]=s;
s-=p[i].x;
}
for(int i=1;i<=n;i++) id[i]=i;
sort(id+1,id+n+1,cmp);
ldb ans=eps;
for(int i=1,j=0;i<=n;i=j+1) {
while (j<n&&p[id[j+1]].y==p[id[i]].y) j++;
for(int k=i;k<=j;k++)
ans=max(ans,query(Point(p[id[k]].y,p[id[k]].y*rpos[id[k]])));
for(int k=i;k<=j;k++)
insert(Point(p[id[k]].y,p[id[k]].y*lpos[id[k]]));
}
for(int i=1;i<=n;i++) s+=p[i].x;
printf("%.10f\n",min(1.0,(double)(s/ans)));
return 0;
}