1. 程式人生 > >ABC 076D - AtCoder Express

ABC 076D - AtCoder Express

expr pan 空間復雜度 span task align end ask tasks

傳送門:http://abc076.contest.atcoder.jp/tasks/abc076_d

本題是一個運動學問題——勻變速運動。

一個質點,從靜止開始運動。按照速度限制,可將運動劃分成n個階段,第i個階段的時間為ti s,速度上限為vi m/s。已知這個質點的加速度大小只取0或±1m/s2。以及,質點在最初和最終的時刻速度為0。求質點的最大位移。

以下變量均采用國際單位制。

對於運動某一個階段(例如第i個階段),可以分成三個子階段:勻加速運動、勻速運動和勻減速運動。記三個子階段的時間分別為inckepdec,則inc+kep+dec=t[i]。記下一個階段的限速為lim,則:

  1. 勻加速階段:inc=
    min{vi-cur,(lim+t[i]-cur)/2,t[i]};
  2. 勻減速階段:dec=max{0,cur+inc-lim};
  3. 勻速階段:kep=t[i]-inc-dec

於是,分別對這三段時間計算位移,求和即可。時間復雜度為O(n2),空間復雜度為O(n)。

參考程序如下:

#include <stdio.h>
#define MAX_N 101

double t[MAX_N], v[MAX_N];

double max(double a, double b)
{
    return a > b? a: b;
}

double min(double a, double
b) { return a < b? a: b; } int main(void) { int n; scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%lf", &t[i]); for (int i = 0; i < n; i++) scanf("%lf", &v[i]); double cur = 0.; double ans = 0.; for (int i = 0; i < n; i++) {
double inc, kep, dec; double lim = 1.E8; double tmp = 0.; for (int j = i + 1; j <= n; j++) { lim = min(lim, v[j] + tmp); tmp += t[j]; } inc = min(v[i] - cur, (lim + t[i] - cur) * .5); inc = min(inc, t[i]); dec = max(0., cur + inc - lim); kep = t[i] - inc - dec; ans += .5 * (cur * 2. + inc) * inc; ans += (cur + inc) * kep; ans += .5 * ((cur + inc) * 2. - dec) * dec; cur += inc; cur -= dec; } printf("%f\n", ans); return 0; }

本題也可以從以下角度考慮:

僅考慮一個區間:若在時間區間[l,r]上的速度上限為v,則在整個時間區間[0,T]上,速度上限函數為

$$f(t)=\begin{cases} v+(l-t),0\le t<l\\v,l\le t\le r\\v+(t-r),r<t\le T\end{cases}$$

其中,$T=\sum_{i=1}^{n}t_i$。

對於階段i,對應的時間區間為$[\sum_{j=1}^{i-1}t_j , \sum_{j=1}^{i}t_j ]$,速度上限為vi,相應的速度上限函數記為fi(t)。考慮所有的區間,則速度上限函數為$f(t)=\min\{t,T-t,f_{i}(t)|1\le i\le n\}$。

由於viti均是正整數,因此可以將t軸的最小單位設置為Δt=0.5s。可以假定從0時刻開始,在每一個Δt=0.5s內,質點的加速度是恒定的。則以Δt=0.5s為單位,用f(t)刻畫質點運動的v-t圖像,並用加速度的限制條件修正v(t)。通過質點運動的v-t圖像計算其最大位移(即v-t曲線與t軸圍成的圖形面積)。時間復雜度為O(nT),空間復雜度為O(n+T)。

參考程序如下:

#include <stdio.h>
#define MAX_N 100
#define MAX_T 40000

int t[MAX_N];
double v[MAX_N], f[MAX_T];

double min(double a, double b)
{
    return a < b? a: b;
}

int main(void)
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &t[i]);
    for (int i = 0; i < n; i++)
        scanf("%lf", &v[i]);
    for (int i = 0; i < MAX_T; i++)
        f[i] = 1.E8;
    int tot = 0;
    for (int i = 0; i < n; i++) {
        t[i] *= 2;
        for (int j = tot; j <= tot + t[i]; j++)
            f[j] = min(f[j], v[i]);
        tot += t[i];
    }
    f[0] = f[tot] = 0.;
    for (int i = 1; i <= tot; i++)
        f[i] = min(f[i], f[i - 1] + .5);
    for (int i = tot - 1; i >= 0; i--)
        f[i] = min(f[i], f[i + 1] + .5);
    double ans = 0.;
    for (int i = 0; i < tot; i++)
        ans += .25 * (f[i] + f[i + 1]);
    printf("%f\n", ans);
    return 0;
}

ABC 076D - AtCoder Express