题目地址
题目大意:kotori有n个设备,每个设备使用速度为 a i a_i ai每秒,一开始的电量为 b i b_i bi,一旦有一个设备电量为0即停止使用,有一个充电宝可以连续给一个设备每秒冲 p p p的电量,求最多这套设备能用多久,如果用之不竭输出-1
数据范围:
1
≤
n
,
p
,
a
i
,
b
i
≤
1
e
5
1\le n,p,a_i,b_i\le1e5
1≤n,p,ai,bi≤1e5
读完题之后,我们会发现这道题珂以二分。二分主体不难写,我们来求最多使用时间,就设两个参数 l l l和 r r r,指 [ l , r ] [l,r] [l,r]区间, m i d = l + r 2 mid=\frac{l+r}{2} mid=2l+r,如果 m i d mid mid参数是可以实现的,那么我们去尝试找更大的答案,即寻找区间 [ m i d , r ] [mid,r] [mid,r],否则答案应该更小,即 [ l , m i d ] [l,mid] [l,mid](注意:这里精度较高,所以不能直接减1,不然直接 G G \color{red}GG GG)
然后就是
c
h
e
c
k
check
check函数了。
对于每种设备,分别有两种情况:
1.原来的电量可以持续
m
i
d
mid
mid秒的时间,即
b
i
a
i
≥
m
i
d
\frac{b_i}{a_i}\ge mid
aibi≥mid ,不用通过充电器额外充电。
2.原来的电量不可以持续
m
i
d
mid
mid秒的时间,即
b
i
a
i
<
m
i
d
\frac{b_i}{a_i}<mid
aibi<mid,需要给予充电。
我们一步步算:
首先,第
i
i
i个设备持续
m
i
d
mid
mid秒的最少电量为
m
i
d
⋅
a
i
mid·a_i
mid⋅ai,如果
b
i
<
m
i
d
⋅
a
i
bi<mid·a_i
bi<mid⋅ai,就需要冲
m
i
d
⋅
a
i
−
b
i
mid·a_i-b_i
mid⋅ai−bi的电量。充电宝每秒冲
p
p
p的电量,即需要充
m
i
d
⋅
a
i
−
b
i
p
\frac{mid·a_i-b_i}{p}
pmid⋅ai−bi秒。
判断是否
m
i
d
mid
mid可以成立的条件:
设第
i
i
i个设备需要充电
t
i
t_i
ti秒,则如果
∑
i
=
1
n
t
i
≤
m
i
d
\sum_{i=1}^nt_i \le mid
i=1∑nti≤mid
这种情况是可以的(因为充电时间没有超过
m
i
d
mid
mid,即可以在充电时间不超过
m
i
d
mid
mid的情况下让所有的设备电量都能维持
m
i
d
mid
mid秒)
否则不成立。
−
1
-1
−1的情况:
科学方法:在
∑
i
=
1
n
a
i
≤
p
\sum_{i=1}^na_i \le p
i=1∑nai≤p
的情况下,用之不竭(充电速度太快了
Q
w
Q
QwQ
QwQ)
考场法:开始的区间设一个比较大的数
R
R
R,从
[
0
,
R
]
[0,R]
[0,R]开始查找,最后答案如果是是
R
R
R就差不多是用之不竭了(
蒟蒻的垃圾码风
c
o
d
e
\color{blue}code
code
# include <bits/stdc++.h>
using namespace std;
#define eps 0.000001
int n,p;
double a[100010],b[100010];
long double ans;
const double RR=1e10*1.0;
bool check(double mid)
{
double tot=0.000;
for(int i=1;i<=n;i++)
{
if(double(b[i])/double(a[i])>=mid) continue;
else
{
double times=double(mid)-double(b[i])/double(a[i]);
double energy=double(times)*double(a[i]);
double f=double(energy)/double(p);
tot=double(tot)+double(f);
// cout<<i<<" "<<times<<" "<<energy<<" "<<f<<" "<<tot<<endl;
}
if(tot>mid) return 0;
}
if(tot<=mid) return 1;
else return 0;
}
inline void js(double l,double r)
{
if(r-l<=eps) return;
double mid=double(l)+double(r);
mid=double(mid)/2.0;
if(check(mid))
{
ans=mid;
js(mid,r);
}
else js(l,mid);
return ;
}
int main(void)
{
scanf("%d%d",&n,&p) ;
for(int i=1;i<=n;i++)
{
cin >> a[i] >> b[i];
}
js(0,RR);
if(RR-ans<=eps) cout<<-1;
else cout<<fixed<<setprecision(400)<<ans<<endl;
return 0;
}
(这题精度有点高啊,卡了我好几次
时间复杂度是
lg
R
\lg{R}
lgR(?
感谢观看(点个关注吧