AOJ 2303 Marathon Match
問題概要
N 人のランナーがマラソンをする.コースの長さは L で,休憩所が途中に M 箇所存在する.i 人目のランナーは,どの休憩所でも全く同じ Pi パーセントの確率で休憩を取る.一度の休憩で Ti だけ時間を使う.また,それぞれのランナーは速度 Vi (一定)で走り続けるものとする.
このとき,i 人目のランナーが優勝する確率を求めなさい.ただし,複数人が同時に最初のゴール者となった場合,優勝したとはみなさない.
・制約
1 <= N <= 100
0 <= M <= 50
1 <= L <= 100000
0 <= Pi <= 100
0 <= Ti <= 100
0 <= Vi <= 100
解法
N, M が小さいので,愚直に確率を求めに行けばいい.具体的には, i 番目の人が j 回休憩したときに,優勝する確率を求め,それらを足していく.
このとき,j 回休憩する確率を求めないといけないが,これはパスカルの三角形の要領(普通にDP)で求めることができる.これは前計算しておけば良い.
i 番目の人が j 回休憩した時,t := L / Vi + Ti * j だけの時間がかかる.この時,k ( != i ) 番目の人が何回以上休憩すれば i 番目の人より遅くゴールするかを考えて,そのそれぞれの回数休憩する確率を足していけば,k 番目の人が i 番目の人より遅くゴールする確率が求まる.
これを i 番目以外の全てのランナーについて考え,掛け合わせれば,i 番目の人が優勝する確率を求めることができる.
ただし,Vk で割ったり,Tk で割ったりする場合があるので,Vk == 0 や Tk == 0 の場合は特別な処理をしないといけない.
また,同時にゴールした場合を省く必要があることもわすれない.
・反省
(ちゃんと考慮してたのに,最後に述べた点で2回WAくらいました.小数に対する処理が甘かった.そもそも何回以上休憩すればオッケーかを求める必要はなくて,とりあえず全部試してオーバーしてたら無視すれば Tk で割ったりする必要は無い.無駄なことをしてしまった.)
計算量は O(N^2M^2) となる.
ソースコード
#include <iostream> #include <vector> #include <cmath> #include <iomanip> using namespace std; constexpr double eps = 1e-10; int main() { int N, M, L; cin >> N >> M >> L; vector<vector<vector<double>>> cmb(N, vector<vector<double>>(M+1, vector<double>(M+1))); for(int i=0; i<N; ++i) { cmb[i][0][0] = 1; } vector<double> P(N), T(N), V(N); for(int i=0; i<N; ++i) { cin >> P[i] >> T[i] >> V[i]; P[i] /= 100; } for(int i=0; i<N; ++i) { for(int j=1; j<=M; ++j) { for(int k=0; k<=j; ++k) { cmb[i][j][k] = cmb[i][j-1][k] * (1 - P[i]) + (k-1 >= 0 ? cmb[i][j-1][k-1] * P[i] : 0); } } } for(int i=0; i<N; ++i) { if(V[i] == 0) { cout << 0 << endl; continue; } double res = 0; for(int j=0; j<=M; ++j) { double t = L / V[i] + T[i] * j; double p = cmb[i][M][j]; for(int k=0; k<N; ++k) { if(i == k || V[k] == 0) { continue; } double tt = L / V[k]; if(T[k] == 0 && tt - t <= 0) { p = 0; break; } int cnt = (T[k] == 0 ? 0 : ceil(max(0.0, t - tt) / T[k])); if(tt + T[k] * cnt - t < eps) { cnt += 1; } double pp = 0; for(int l=cnt; l<=M; ++l) { pp += cmb[k][M][l]; } p *= pp; } res += p; } cout << fixed << setprecision(10) << res << endl; } }