算法1
(模拟) O(N)
直接按题意模拟即可。
我们可以通过比较左右两边燃烧完某一整段的时间来更新答案:
若左边燃烧完某一整段的时间小于右边燃烧完某一整段的时间的话,则用当前左边花的时间来更新答案;
反之,则用当前右边花的时间来更新答案。
重复以上过程,直到两个小火苗停留在同一段上。这时把这两点距离的一半加进答案即可。
C++ 代码
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using std::cin;
using std::cout;
using std::vector;
int main() {
int n;
cin >> n;
vector<double> a(n), b(n);
rep(i, n) cin >> a[i] >> b[i];
int li = 0, ri = n-1;
double lx = 0, rx = 0;
double ans = 0;
while (li < ri) {
double lt = (a[li] - lx) / b[li];
double rt = (a[ri] - rx) / b[ri];
if (lt < rt) {
ans += b[li] * lt;
lx = 0; rx += b[ri] * lt;
li++;
}
else {
ans += b[li] * rt;
rx = 0; lx += b[li] * rt;
ri--;
}
}
ans += (a[li] - lx - rx) / 2;
printf("%.10f\n", ans);
return 0;
}
算法2
(思维) O(N)
注意到,若两个小火苗相遇的话,那么他们所花的时间必然是相同的,所以我们只需考虑燃烧完所有引线需要的时间的一半,记为 t。然后从前往后扫描每个引线燃烧完需要的时间 nt,若 nt⩽,则把当前的引线长度加入答案,同时把 nt 从 t 中减去;若 nt > t,则把当前引线的燃烧速度与 t 的乘积加进答案即可。
C++ 代码
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using std::cin;
using std::cout;
using std::vector;
int main() {
int n;
cin >> n;
vector<double> a(n), b(n);
rep(i, n) cin >> a[i] >> b[i];
double t = 0;
rep(i, n) t += a[i] / b[i];
t /= 2;
double ans = 0;
rep(i, n) {
double nt = a[i] / b[i];
if (nt > t) {
ans += b[i] * t;
break;
}
ans += a[i];
t -= nt;
}
printf("%.10f\n", ans);
return 0;
}