这道题我用的是二分答案,只不过这道题和一般的二分答案有些不同,是浮点数的二分答案。那自然和整数的二分答案有些不同,下面我会说到。我们先来看一下思路解法。
思路解法
首先确定了是二分答案,我们需要先确定初始的 \(l\) 和 \(r\) 和 check 函数。
check 函数好写,我们可以根据
\[t_i = \frac{d_i}{s_i+c} \]这个公式来求出每段路程的时间。最后将总和与 \(t\) 比较,判断当前二分到的 \(c\) 的大小。
那如何判断 \(c\) 是大还是小呢,我们回到上面那个公式,如果 \(t_i\) 的总和比 \(t\) 要大,说明 \(c\) 小了,那应该去右半区间中找 \(c\)。
接下来我们来确定初始的 \(l\) 和 \(r\)。我们再回到上面的公式中,可以看出 \(s_i+c > 0\),那么所以 \(c > -s_i\) 所以 \(l\) 应取 \(s_i\) 最小值的相反数。
通过数据范围可以看出 \(t_i\) 的最大值为 \(10^6\),\(s_i\) 的最小值为 \(10^3\),所以 \(c\) 的最大值为 \(10^6 - 10^3\)。大家可以尝试根据上面的公式推一下,不过 \(r\) 的最大值可以取得大一些,无非就是多循环几次,影响不大。
不过此题还是有几个点需要注意的:
首先就是浮点数的二分答案和整数的二分答案的区别。因为题目中说明了输出与正确答案的差应在 \(10^6\) 以内,所以循环的判断条件应为 while((r-l)>=1e-7)
。
同时浮点数是不能使用位运算的,所以应为 mid=(l+r)/2
。
第二个需要注意的地方是翻译有点问题,题目中的单位均为英里和英里每小时,所以是不需要单位转换的。
最后一个也是最坑的地方,除了 \(n\) 输入为整数,其他的输入时均为实数,所以应该使用 double
而非 int
。
代码
#include<iostream>
#include<cstdio>
using namespace std;
int n;
double t,d[1005],s[1005],l=1e9,r=2e6;
bool check(double c){
double ans=0;
for(int i=1;i<=n;i++){
ans+=(d[i])/(s[i]+c);
}
return ans>=t;
}
int main(){
scanf("%d%lf",&n,&t);
for(int i=1;i<=n;i++){
scanf("%lf%lf",&d[i],&s[i]);
l=min(s[i],l);
}
l=-l;
while((r-l)>=1e-7){
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
printf("%.7f",l);
return 0;
}
标签:P6933,二分,10,int,题解,mid,答案,double
From: https://www.cnblogs.com/yzxgg/p/solution-p6933.html