AOJ 1056 Ben Toh
n日までに得る弁当の総数の期待値を計算すればいいわけだが、漸化式がうまく作れない && 他の人のコードを読んでも自明のようにdpしていてよく分からない、というツラさがあったので、この問題の漸化式が私のように漸化式が思いつかなかった人のために愚直に式の導出をする(もっとスマートに立式できる方法があったら教えて下さい)。
: n日までに得る弁当の総数
: n日目に弁当を得る確率
: n日目に弁当を得て、それまでにk-1回連続で弁当を得ている確率
期待値の性質からなので、の漸化式を求めればよい。
ここでについて以下の漸化式が成り立つ。
上式を繰り返し用いて、
ゆえに、
ここで、であるからのとき、
であるから、これでを逐次的に求めることができる。
解答の上ではがdouble型の有効桁数よりも小さい範囲で和を取れば十分である。
#include <bits/stdc++.h> using namespace std; #define REP(i,n) for(int i=0;i<(int)(n);i++) double memo[100001]={}; double cff(int k){ if(k>=20) return 0.0; return pow(2.0,-k*(k-1)/2); } double dp(int n){ if(n==1) return memo[1]=1.0; if(memo[n]>1e-10) return memo[n]; double res=cff(n); for(int k=1;k<=min(n-1,20);k++){ res+=(1-dp(n-k))*cff(k); } return memo[n]=res; } int main(){ int n; while(cin >> n && n){ double res=0; for(int i=1;i<=n;i++) res+=dp(i); cout << fixed << setprecision(10) << res << endl; } return 0; }