TopCoder SRM504.5 Div1Hard
こんな易しいDiv1Hardがあってたまるか
問題
1列に人が並んでいて、次の操作を行う。
「2人以上いるなら、サイコロを振って、4が出たら先頭の人を選ぶ。1,3,5が出たら先頭の人は一番後ろに並ぶ。2,6が出たら先頭の人は家に帰る。並んでいるのが1人だけなら、その人を選ぶ。」
最初に列にN人並んでいる。最初にM番目にいる人が選ばれる確率を求めよ。
解答
(N, M)における答えをdp[N][M]として考える。
すると、M=1のとき、dp[N][M] = 1/6 + 1/2*dp[N][N]で、M>=2のとき、dp[N][M] = 1/2*dp[N][M-1] + 1/3*dp[N-1][M-1]がわかる。
また、dp[1][1]=1.0であるから、dp[2][i]、dp[3][i]、…と順番に解いていけば良い。
コード
#include <cstdio> class TheTicketsDivOne { double dp[1001][1001]; double tmp[1001]; public: double find(int N, int M) { dp[1][1] = 1.0; for(int i=2;i<=N;i++){ tmp[1] = 1.0 / 6.0; for(int j=2;j<=i;j++){ tmp[j] = dp[i-1][j-1] / 3.0; } double x1=tmp[1], x2=0.5; for(int j=2;j<=i;j++){ x1 = (x1/2.0)+tmp[j]; x2 = x2/2.0 + 0.5; } dp[i][i] = x1 / x2; dp[i][1] = 0.5 * dp[i][i] + tmp[1]; for(int j=2;j<i;j++){ dp[i][j] = 0.5 * dp[i][j-1] + tmp[j]; } } return dp[N][M]; } };