今日 yukicoder contest 411 オムニバスコンテスト - yukicoder というコンテストにて, はちじさん Writer の問題 Yellow Cards が公開されました. 自分は Tester をさせていただきましたが, そこで別解を見つけたので書きたいと思います. この方法では, という制約で解くことが可能であり, 想定解法より高速です.
あらすじ
想定解と少し違う角度で問題を眺めることで, 問題の答えは について 次の線形漸化式で表すことができます.
行列の 乗を繰り返し二乗法で求め, として時間計算量 などで解くことができます.
解法
次の見方で考えます:イエローカードが 回目に出されたとき, 仮想的に変数「退場人数」に を足すだけでその人は退場させず, その人のイエローカードの回数を にリセットする.
とくに, 退場人数が増える瞬間は「イエローカードの状態が に行ったとき」だけです.
ある 人についての答えへの寄与を求めたいと考えます. 他の人の寄与も対称性から同じであるため, ある 人の寄与が求まれば, それを 倍することで全員の寄与の合計がわかります. ある 人を A さんとします.
現在の「状態」を, A さんのイエローカードの回数を で割った余りとします. A さんにイエローカードが出されたとき (確率 ), 状態は から に変化します. 他の人にイエローカードが出されたとき (確率 ), 状態は から に変化します.
よって, を「 回目のイベント直後の状態が である場合の数」とすると, 行列を用いて
と表されます. ここで, ケーリー・ハミルトンの定理によって次が分かります:
. いま ということで, の母関数は
となります.
退場人数が増える瞬間は「イエローカードの状態が に行ったとき」であることを思い出します. で状態が に行くチャンスがあり, その確率は, から確率 で起きます. よって, 回目のイベントで A さんが退場回数に寄与する分の母関数は
となります. したがって, Aさんの合計の退場回数の期待値は, での退場回数への寄与の累積和であることから, 母関数で表すと
となります. よって, 前半に述べたようにこれを 倍して, 全体での合計退場回数の期待値は
となります. これは線形漸化式を表し, 行列累乗 (Bostan-Mori などでもよい) で計算できます. 計算量は として 時間です.
具体的に, 数列 を として,
を計算すればよいです.
以下は C++17 (ACLあり) での Bonus 解法の実装です. yukicoder.me
補足
閉じた式があることを教えてもらいました. ありがとうございます.
証明:WolframAlpha
WolframAlpha に頼らない証明としては, 母関数を級数展開したときの総和を考えたり, 部分分数分解したりするのがいいと思います.
よって以下が答えです.
補足2
母関数を使わないで高速に求める方法を教えてもらいました. ありがとうございます!
解説にもあるように, イエローカードを奇数回もらう人が 人いたとすると, 答えは であることに注意します. つまり, 各人について「イエローカードが奇数回になる確率」を求めればよいです.
各人がイエローカードを 回もらう確率は, 各イベントについてイエローカードをもらわない確率が , もらう確率が であることから,
となります. すべての奇数 について, 上の値の総和を求めたいです. ここで, で割った余りが である次数の係数全部の和―― というときに使える一般的なテクニックを使うと, 答えは を上に示した多項式として,
となります. これは 1 人分の答えの寄与なので, 最終的には N 倍します. 答えの式に注意すると, 答え
を得ます.