確率を確実に
問題概要
正の整数 が与えられる。
最初に の整数値をランダムに出力する。以降コインを振って
- 表が出たら整数値を 2 倍する (
以上になったら「勝ち」でゲーム終了)
- 裏が出たら整数値を 0 にする (こうなった時点で「負け」でゲーム終了)
というのを繰り返す。勝ってゲームを終了する確率を求めよ。
制約
考えたこと
制約が小さいので、最初に出てくる数値をすべて試すことができる。具体的には
- 最初に
が出る確率は
になる
- さらにそこから勝つ確率は、
からスタートして
以上になるまで表が出続ければよくて、表が出る必要のある回数を
とすると、
になる
ということで、合計して、
となる。これを について合計すれば OK。
最後に気になるのは (各
からスタートして
以上になるまでに出し続ける必要のある表の回数) の求め方だが、これは愚直に
int n = 0; while (v < K) v *= 2, ++n;
とかで大丈夫。このとき は指数的に大きくなるので、計算回数は
で抑えられる。以下の実装ではさらに、
の計算も while 文の中でまとめて行うこととした。全体として計算量は になった。
#include <iostream> #include <iomanip> using namespace std; int main() { long long N, K; cin >> N >> K; double res = 0.0; for (long long n = 1; n <= N; ++n) { double tmp = 1.0; long long nn = n; while (nn < K) nn *= 2, tmp /= 2.0; res += tmp; } res /= N; cout << fixed << setprecision(10) << res << endl; }