AtCoder Beginner Contest 189 F - Sugoroku2
ABC 反省文シリーズです。
問題リンク
https://atcoder.jp/contests/abc189/tasks/abc189_f
問題概要
マス から始めてマス を目指す双六があります。高橋くんは から までの目が出るルーレットを回して進みます。また、この双六のマス は振り出しに戻るマスで、そこに止まるとマス に戻されます。
高橋くんがマス より先に着きゴールするまでにルーレットを回す回数の期待値を求めてください。到達不可能ならその旨を報告してください。
制約
考察
まず、 個以上連続して振り出しに戻るマスが存在したら到達は不可能です。そうでないときを考えます。
見た目からして期待値 DP です。期待値 DP を考えます。期待値を求めるときの定石ですが、初手からその状態になるまでの期待値ではなくその状態からゴール状態になるまでの期待値を考えると往々にして上手くいきます1。今回も実際に初手からその状態になるまでの期待値を求めると非常に難しくなってしまうので、逆から考えることにします。
さて、 をマス から に辿り着くために必要なルーレットを回す回数の期待値と定義します。このとき、「振り出しに戻る」でないマスについては次のような遷移となります。
これは、 個先のマスにそれぞれ の確率で到達し、ルーレットを回す回数はどの場合も 増えることから分かります。ただし、 と便宜上定義します。
そうでないとき、つまり「振り出しに戻る」マスのときはどういう遷移となるでしょうか。「振り出しに戻る」マスに止まるとその次はマス からやり直しになるため、最初からゴールするまでの期待値そのものが必要なルーレットを回す回数の期待値となります。よって、このときは
となります。
ここで、期待値を求める際には期待値が満たすべき方程式を解いて求めても良い2ということを思い出します。たとえばサンプル 2 を例にして考えると、
- が出たら振り出しに戻る。
- が出たらゴールする。
のそれぞれの起こる確率は です。求めるべき期待値を と置くと、マス から まで行くのに必要な回数の期待値はそれぞれ なので、マス から まで行くのに必要な回数の期待値 は を満たすことが分かります。よって、この方程式を解いて とするとこれが答えになっています。
話が逸れましたが、以上のような DP テーブルの遷移をしていくと、 は の一次式 で表されることが分かります。ここで、遷移からも分かりますが はゴールするまでに振り出しに戻る確率ですので、到達可能であることと となることは同値です。よって、 として期待値を求められます。DP の遷移は それぞれを Segment Tree に乗せて行うことができます。
解法
個以上連続して振り出しに戻るマスが存在したら到達は不可能です。そうでないときを考えます。
Segment Tree 上で DP を行います。 を、 がマス からゴールするまでに必要なルーレットを回す回数の期待値となるような一次式と定義します。実装上は をそれぞれ別の Segment Tree で保持するか、面倒なら Pair として持つかすれば良いでしょう。
ただし、便宜上 と定義します (全部 なので より後ろは足切りする実装でも良いです)。
後ろから順に見ていき、マス が振り出しに戻るマスでないときは
振り出しに戻るマスであるときは
というふうに漸化式が立ちます。答えは です。
実装
実装を展開する
public void Solve() { var (n, m, k) = sr.ReadValue<int, int, int>(); var a = sr.ReadIntArray(k); var skip = new bool[n + 1]; for (int i = 0; i < k; i++) { skip[a[i]] = true; } var e = new SegmentTree<double>(n + 1, (x, y) => x + y, 0); var x = new SegmentTree<double>(n + 1, (x, y) => x + y, 0); for (int i = n - 1; i >= 0; i--) { var ok = false; if (m <= 10) { for (int j = 1; j <= m; j++) { if (i + j < n + 1 && !skip[i + j]) ok = true; } } else ok = true; if (!ok) { Console.WriteLine(-1); return; } if (skip[i]) { e.Update(i, 0); x.Update(i, 1); } else { e.Update(i, e.Prod(i + 1, Min(n + 1, i + m + 1)) / m + 1); x.Update(i, x.Prod(i + 1, Min(n + 1, i + m + 1)) / m); } } Console.WriteLine(e[0] / (1 - x[0])); }
ACコード: https://atcoder.jp/contests/abc189/submissions/19662693
感想
期待値 DP が得意なほうなはずのにこの問題を落としちゃいけないと思いました。なんで後ろから見るっていうのが分からなかったんだろう……ひとつの解法にハマってしまったときのリカバリ方法もちゃんと普段から意識しておかないといけませんね。
-
期待値 DP では本当によくある手法で、以前解説記事を書いた ABC184-D - increment of coins も同じように逆から考えます。ABC184-D ではすぐに思いついたのにこの問題では全く思いつかなかったので自分でもなんで?????になりました。↩
-
これは期待値に限らず数列の極限でも定石のテクニックだと思います。高校数学・大学入試数学ではその正当性や解の存在条件などを示すのが面倒であることから疎まれがち (特性方程式みたいなものですね……) ですが、競プロでは解の存在さえ示せるなら断りなく使ってもいいと思います。↩