Xmas Contest 2018 D: Devilish Dice 解説
https://atcoder.jp/contests/xmascon18/tasks/xmascon18_d
問題概要
個の 面さいころの目を上手く決めて,「どのさいころについても,他のあるさいころを選ぶと確率 以上でそれより大きい目が出せる」となる を最大化せよ.
考察
くろうさ「先にさいころ選んでいいよ」
しろうさ「やさしい」
くろうさがやさしいわけはなく (?), かつ ではこれはくろうさ有利なゲームです.例えば, という 個のさいころを考えると, となり,三竦みの関係が生じます.他にも大量の例が https://en.wikipedia.org/wiki/Nontransitive_dice に載っています.
とても手に負えなさそうですが,問題を単純化できる考察がいくつかあります.まず,別のさいころに同じ値を書く意味はありません.同じ値があるとき片方を少し増やしてもくろうさは何も損しないからです (くろうさの勝率 の中身が増えるだけなので).
また,「 竦み」のような関係のみ考えればよいです.あるさいころに対して,それに強いさいころ,さらにそれに強いさいころ,……というようにとっていくとサイクルができるので, に対する,「 となる最大の 」で答えが上から抑えられます.逆にこういうサイクルをひとつ作ってしまえばあとは弱いさいころを好きなだけ足せばよいです.
解法 1
ここまでを念頭にマシンパワーで DP をします. を固定します.
さいころ の順で目を決めていくことにすると, を決めるときには と 以外の情報は要りません.ということで, と の目の大小関係を状態 ( 通り) として, を最大化する DP をします.
DP の遷移をするには, と の大小関係それぞれに対する, と と の大小関係 ( 通り) が一見要りそうですが, と の大小関係を決めてしまえば十分で,なぜならその制約の下では を に対してできるだけ強くしてしまってよいためです.
DP テーブルをどの まで作るかですが,やってみるとそのうち変わらなくなるので打ち切れます ( なら実は までしか要りません).あるいは後述のように に対する勝率の上限を求めておいてそれを達成したら打ち切る,というのもできます.
こんな感じで, に多項式がかかったような計算量で解けるので,がんばって回して答えを埋め込みましょう.細かい定数倍高速化としては,例えば「 が目の最大値を持つことにしてよい」を採用すると 倍速くなって嬉しいです.わたしのコードは実行時間 分くらいでした.
japlj さんと snuke さん は,ちょっと別のアプローチのマシンパワー探索解法をしていました.答えを決め打って必要な を求めにいく方針で,枝刈りが上手く効くようです.
解法 2
いろいろ実験をすると,「 番目のさいころには と しか書かない」というパターンで結構いい感じの勝率が得られていそうなことに気づけるかもしれません (後述のように,これはただの偶然でも突拍子もない発想でもないです).実際に ではこれですべて正解できるようです.
コンテスト中の hogloid さん,終了直後の omeometo さんの解法がこのパターンを見つけた方針でした.コンテスト前には,snuke さん作のゲームを手で遊んだ結果から似たようなパターンを試していたのですが,変な greedy をしていて で不正解になっていたので,全探索系以外は厳しいかも?と思っていたのでした.
このパターンを仮定するなら,いろいろな解法が考えられます.例えば,「 番目のさいころの の個数」と「 番目のさいころの の個数」を状態として持つ DP ( 時間) が楽だと思います.
さて,この仮定が正しいかというと,実は反例があるようです. で,
144444444444444444444444444 222222222225555555555555555 033333333333333336666666666
というさいころを考えると,くろうさの勝率は ですが, 値さいころだけではこれは実現できません.ただ,この反例のように,「 に対しては 番目のさいころには と しか書かない, 番目のさいころには と と しか書かない」というパターンなら正しいのではないかと予想しています.証明を募集しています!!
参考 1 (fixed K)
を固定したときの勝率の最大値は です.
これは,「中央値が最小」みたいなさいころを考えることで上から抑えられます.正確には, 竦みの中で自身の 番目の値が最小のさいころを考えると,それは他のさいころに高々 でしか勝てないので, ととることで示せます.この評価の仕方は, 値さいころだけを考えてもかなり上手くいくことを示唆しているかもしれません.
最大値をとる具体的な構成もできて,例えば として,「 番目のさいころには が 個で残りは 」というようにすればよいです ( はもっと小さくとれます).
とするとこの値は になります.さいころに限らない一般の確率分布を考えても,勝率は が上限ということですね.
参考 2 (fixed N)
を固定したときの勝率の上限は です (!?). ではそれぞれ となります.
詳しくは https://mathoverflow.net/a/119885 をご覧ください.
わたしは証明をちゃんと把握できていないのですが, 値の確率分布だけを考えればよいことを示すという方針のようです. が固定されているときに同じ議論は適用できないのですが, 値さいころだけを考える有力な根拠となります.解法 の最後で述べた予想も, を固定したときの最適解を近似したものがベストだろう,という考えに基づいています.
コメント
三竦みが作れるってだけでも面白いのにいろいろ楽しい数学が奥に潜んでいる,という感じの話題を,全部有限にして探索力 and/or 数学センスを問う問題にしてみました.不思議な問題ですね.
Xmas Contest 2018 C: CombinatioN 解説
https://atcoder.jp/contests/xmascon18/tasks/xmascon18_c
問題概要
Pascal の三角形を書こうとしたが,ある場所で足し算を大きい値に間違えてしまった (→間違いがそこから伝搬).そして一部消えてしまった.というものが与えられるので,間違えた場所を特定せよ.
部分点解法
で間違えて 大きい値を書いてしまったときの影響を考えると, かつ を満たす のところが だけ大きくなることがわかります.
これを用いると,すべての を間違えた場所の候補として,与えられた条件がすべて満たされているか調べる,という解法が得られます (増えているところの情報から の値を求めて,複数個になったらダメ). 時間になります.
解法 1
制約をよく見ると,消えずに残っている値は 以下と書いてあります.ということは,正しい値以上が書いてある場所は なところしかありません.これは よりだいぶ少なくて, では 箇所です.
大きい方にしか間違えないので,正しい値未満が書いてあったら IMPOSSIBLE
です.これで弾かれなければ,部分点解法で間違えた場所 を決め打ったあと調べる箇所が から になるので,間に合うかもしれない気がしてきます.実際,実装の定数倍や言語次第かもしれません.
もう少し速くするには,間違えた場所の候補 を試すとき, なら間違えても情報が出てこない,ということを用います.まとめるとこんな感じ:
正しい値未満が書いてあったら IMPOSSIBLE foreach (i, j): if check(i, j): (i, j) を答えの候補に追加 答えの候補が 0 個なら IMPOSSIBLE,1 個ならそれを出力,2 個以上なら AMBIGUOUS function check(i, j): if C[i][j] > 10^9: 正しい値より大きい値が書いてあれば return false // これは前計算しておく return true foreach 何か書いてある (k, l): if k >= i and l >= j: x := (A[k][l] - C[k][l]) / C[k - i][l - j] x が正の整数でなければ return false x を x の候補に追加 else: A[k][l] = C[k][l] でなければ return false x の候補が 2 個以上なら return false return true
これなら一番計算が重い部分が で,無事間に合います.
解法 2
正しい値より大きい値が書いてある場所 をひとつ決めると,間違えた量 は の約数なので,それをすべて試します.正しい値より大きい値が書いてあるという情報から,間違えた場所 がどんどん絞られていきます.というのも, の値から と がほぼ決定されるからです ( のときを除いて,最大 通りしかないようです).
計算量のボトルネックは, とかになります.実装は結構大変かもしれません.さらに,AMBIGUOUS
等の判定で間違えがちです:例えば,一番下の段でひとつだけ消えていて,他が全部正しいとき,正しい値しか書いていないですが間違えた場所は一意に特定されます.
コメント
適当に問題設定を考えついて,最初は約数を調べる解法を思いついて適当に投下したのですが,snuke さんがすぐに言ってきた素直に全箇所調べる解法が十分速いことに気づき,簡単めでいいかな~と思って採用されました.しかしはまりがちポイントが大量にあることが徐々に発覚し,綺麗な実装ができますかという問題に.一発で通せた方はすごい!
Xmas Contest 2018 B: Bit Smaller 解説
https://atcoder.jp/contests/xmascon18/tasks/xmascon18_b
問題概要
とか, とか,そういうののうち 以下のものをすべて求めよ.
解法 1
全探索しましょう.数の切り方は高々 通りしかないのでなんとかなると思います.
先頭のほうから切っていく感じで再帰で実装するのもよいと思います.
枝刈りとかがんばらない限りは実行にそれなりに時間がかかりますが (わたしのは数分でした),答えだけ出せばいいので安心.
たちの積を求めていくより で 回割っていく,みたいなののほうがオーバーフローを気にせずに済んで枝も刈れていろいろお得かも (ただし に注意).
解法 2
親切にもふたつめの答えまで書いてあるので OEIS で検索すると見つかります.が,
- "not ending with 0" と書いてあるように,条件を満たす数の末尾に をつけてもやはり条件を満たす
- 切り分けたときに が入っていたり で始まっていたりそういうのも含まれている
ことに注意してください.
コメント
面白算数 (?) ネタを見つけたので易しめの問題にしてみました.作問陣は OEIS で検索するのをすっかりさぼっていたのですが,微妙に条件が違って逆にトラップになってたようで面白いですね.
この問題の範囲では一の位が (か ) の解しかないですが,他がないわけではないです (問題概要のとこの例とか).
みたいに最後の部分がないパターンも綺麗ですが,探索で見つかる範囲だと全然ないようです.桁を増やせば,例えば とかがあります (見た目がやばいですがこうやって構成されています: https://math.stackexchange.com/a/2126667).