AGC 007 D - Shik and Game

D - Shik and Game

链接

题意:

  数轴上有一个人,从0出发到E,速度为1。数轴上还有n只熊,每只熊会在经过后的T时刻后产生一个金币。给定E,T以及n个熊的坐标pi,求收集完所有金币并到达E的最短时间。N≤105,E,T≤109

分析:

  首先由转移方程:$f_i = f_j + p_i - p_j + max\{T,2 \times (p_i - p_{j + 1})\}$

  因为一定是要走完E的距离,所以可以写成$f_i = f_j + max\{T,2 \times (p_i - p_{j + 1})\}$,最后加E。

  对中间的max讨论一下,$f_i = f_j + T$, $f_i = f_j + 2 \times (p_i - p_{j + 1})$,然后转移点j具有单调性,可以维护。

  后面的变成$f_i = f_j + 2 \times p_i - 2 \times p_{j + 1}$,发现对一段前缀取$f_j - 2 \times p_{j + 1}$的最小值。

  时间复杂度$O(n)$

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 1000005;
LL f[N], p[N];

int main() {
    int n = read(), E = read(), T = read();
    for (int i = 1; i <= n; ++i) p[i] = read();
    LL Mn = 1e18;
    int j = 0;
    for (int i = 1; i <= n; ++i) {
        while (j <= i && 2 * (p[i] - p[j + 1]) > T) {
            Mn = min(Mn, f[j] - 2 * p[j + 1]);
            ++ j;
        }
        if (j < i) f[i] = f[j] + T;
        f[i] = min(f[i], Mn + 2 * p[i]);
    }
    cout << f[n] + E;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/mjtcn/p/10334045.html