今日
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 倍します. 答えの式に注意すると, 答え
を得ます.