ABC 076D - AtCoder Express
傳送門:http://abc076.contest.atcoder.jp/tasks/abc076_d
本題是一個運動學問題——勻變速運動。
一個質點,從靜止開始運動。按照速度限制,可將運動劃分成n個階段,第i個階段的時間為ti s,速度上限為vi m/s。已知這個質點的加速度大小只取0或±1m/s2。以及,質點在最初和最終的時刻速度為0。求質點的最大位移。
以下變量均采用國際單位制。
對於運動某一個階段(例如第i個階段),可以分成三個子階段:勻加速運動、勻速運動和勻減速運動。記三個子階段的時間分別為inc、kep、dec,則inc+kep+dec=t[i]。記下一個階段的限速為lim,則:
- 勻加速階段:inc=
- 勻減速階段:dec=max{0,cur+inc-lim};
- 勻速階段: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, doubleb) { 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\}$。
由於vi、ti均是正整數,因此可以將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