HDU 6581 Vacation 思维或者二分答案

HDU 6581 Vacation

题目链接

题目大意:Tom所处的车是0号车,道路是单行道,不能超车,Tom前面有n辆车,每辆车都有l, s, v三种属性,分别代表车长,车头距离终点线的距离,车的最大速度。当一辆车没有追上前面的车时,这辆车以最大速度行驶,当追上前车时(前车车尾和这俩车车头距终点线距离相等),这辆车以前车的速度继续行驶。所有车子过了终点线后仍然会行驶,求Tom的车到终点线(车头到终点线)的最短时间。答案要精确到1e-6。

有两种解法,比较直观的应该是二分,直接二分时间来得到答案。

 

二分解法:

由于头车不受阻挡,可以一直以全速前进,在特定的时间点,我们可以求出头车距离终点线的距离,从而可以向后递推出后面每一辆车距离终点线的距离。而且可以轻松得出一个结论:时间越大,0号车走的路程也必定越长,有单调性。

对于第i辆车在时间点t,有

dis[i] = max(s[i] - t * v[i],  dis[i + 1] + l[i + 1])

dis[i]表示i号车距离终点线的距离, i + 1号车是前一辆车

通过最后的dis[0]来check 0号车和终点线间的状态

if (dis[0] > 0) l = mid; //没到终点线,扩大范围

else r = mid;

而且我们dis[i]的状态只和dis[i + 1]有关,把dis[]换成变量pos滚动即可

代码如下:

#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
#define N 100005

double l[N], s[N], v[N];

int n;
bool check(double t) {
    double pos = s[n] - v[n] * t;
    for (int i = n - 1; i >= 0; i--) {
        pos = max(s[i] - v[i] * t, pos + l[i + 1]);
    }
    if (pos > 0) return 1;
    else return 0;
}

int main() {
    while (scanf("%d",&n) != EOF) {
        for (int i = 0; i <= n; i++) scanf("%lf",&l[i]);
        for (int i = 0; i <= n; i++) scanf("%lf",&s[i]);
        for (int i = 0; i <= n; i++) scanf("%lf",&v[i]);
        double l = 0.0, r = 1111111111111, mid;
        while (r - l > 1e-7) {
            mid = (l + r) / 2;
            if (check(mid)) l = mid;
            else r = mid;
        }
        printf("%f\n",mid);
    }
    return 0;
}

 

O(n)的思维解法

0号车到达终点时,可能会和前面一些车贴在一起共速,这些车一定是连续的,枚举0号车和它前面贴在一起的车的数量,计算每一次0号车通过终点的时间,从中取一个最大值就是答案。

和前面贴在一起的车的数量为0:t0  = s[0] / v[0];

和前面贴在一起的车的数量为1:t1 = (s[1] + l[1]) / v[1];

和前面贴在一起的车的数量为2:t2 = (s[2] + l[2] + l[1]) / v[2];

以此类推,取其中的最大值就是答案

复杂度是O(n) ,实现也更简单

代码如下:

#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
#define N 100005

double l[N], s[N], v[N];

int main() {
    int n;
    while (scanf("%d",&n) != EOF) {
        for (int i = 0; i <= n; i++) scanf("%lf",&l[i]);
        for (int i = 0; i <= n; i++) scanf("%lf",&s[i]);
        for (int i = 0; i <= n; i++) scanf("%lf",&v[i]);
        double ans = 0.0;
        double len = 0.0;
        for (int i = 0; i <= n; i++) {
            if (i > 0) len += l[i];
            ans = max(ans, (s[i] + len) / v[i]);
        }
        printf("%.8f\n",ans);
    }
    return 0;
}

 

你可能感兴趣的:(训练赛总结)