AOJ 2303 - Marathon Match
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2303
概要
N 人の人がマラソンをする.
途中 M 箇所に休憩所があり,i 番目の人は確率 P[i]
で休憩を T[i]
だけとる.
i 番目の人は一定の速度 V[i]
で走る.
マラソンの長さは L である.
このとき,i 番目の人が優勝する確率をそれぞれ出力する. ただし,2人以上同時に最初にゴールしたときは,優勝者はいないことにする.
制約
- 1 <= N <= 100
- 0 <= M <= 30
- 1 <= L <= 100000
- 0 <= P[i] <= 100
- 0 <= T[i] <= 100
- 0 <= V[i] <= 100
解法
ps[i][j] = i 番目の人が j 回休憩をとる確率
という表と,
ts[i][j] = i 番目の人が j 回休憩をとったときにかかる時間
という表を作って計算する.
i 番目の人が優勝するのは,
Σ_j Π_k P(ts[k][l] < ts[i][j])
で求められる.
P(ts[k][l] < ts[i][j])
を計算するとき,ps[i][j]
の累積和を予め計算しておくと二分探索により log M
で計算でき,
全体として O(N * M * N * log M)
で計算できる.
コーナーケースとして
V[i] = 0 (i = 1 ... N)
がある.これはひどい…
aoj/2303.cc1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <algorithm> 5 #include <cmath> 6 using namespace std; 7 static const double EPS = 1e-7; 8 9 struct runner { 10 int p, t, v; 11 }; 12 13 int main() 14 { 15 static double comb[55][55]; 16 for (int i = 0; i <= 50; i++) { 17 comb[i][0] = 1.0; 18 } 19 for (int i = 1; i <= 50; i++) { 20 for (int j = 1; j <= i; j++) { 21 comb[i][j] = comb[i-1][j-1] + comb[i-1][j]; 22 } 23 } 24 25 int N, M, L; 26 cin >> N >> M >> L; 27 vector<runner> v; 28 bool all_zero = true; 29 for (int i = 0; i < N; i++) { 30 runner r; 31 cin >> r.p >> r.t >> r.v; 32 v.push_back(r); 33 if (r.v != 0) { 34 all_zero = false; 35 } 36 } 37 38 if (all_zero) { 39 for (int i = 0; i < N; i++) { 40 cout << "0.0000000" << endl; 41 } 42 return 0; 43 } 44 45 vector<vector<double> > ps(N, vector<double>(M+1)); 46 vector<vector<double> > ps_integral(N, vector<double>(M+1)); 47 vector<vector<double> > ts(N, vector<double>(M+1)); 48 for (int i = 0; i < N; i++) { 49 for (int j = 0; j <= M; j++) { 50 ps[i][j] = pow(v[i].p/100.0, j) * pow((100-v[i].p)/100.0, M-j) * comb[M][j]; 51 if (j == 0) { 52 ps_integral[i][j] = ps[i][j]; 53 } else { 54 ps_integral[i][j] = ps_integral[i][j-1] + ps[i][j]; 55 } 56 ts[i][j] = double(L)/v[i].v + v[i].t*j; 57 } 58 } 59 60 for (int i = 0; i < N; i++) { 61 double ans = 0.0; 62 for (int j = 0; j <= M; j++) { 63 double p = 1.0; 64 for (int k = 0; k < N; k++) { 65 if (k != i) { 66 int l = lower_bound(ts[k].begin(), ts[k].end(), ts[i][j]+EPS) - ts[k].begin(); 67 if (l != 0) { 68 p *= (1.0 - ps_integral[k][l-1]); 69 } 70 } 71 } 72 ans += ps[i][j] * p; 73 } 74 printf("%.6f\n", ans + EPS); 75 } 76 return 0; 77 }