Codeforces 1119H: Triple
https://codeforces.com/problemset/problem/1119/H
問題概要
が固定されている. に対して が与えられるので, たちを の指数は XOR で畳み込む,というのを速くやる.
考察
Hadamard 変換すれば畳み込みが掛け算になる (常識) けど,そのままやると長さ の列を 個作らなければいけなくてダメ.
を Hadamard 変換すると 項目は になる ( は ビットの整数を長さ のベクトルと見た内積) (定義).ので,出てくる値は しかない (これは定義に戻ることを忘れていても実験すればわかる).ので, 項目の積は みたいになって ( とかは に依存), とか関係なくて 個の指数が上手く求まればうれしい.例えば は が全部偶数になるような の個数とかそういう.手早く数えられそうでできない (「数える」という考えから抜けられなくてコンテスト中はここで止まった).
「 とか関係なくて」とか言ったんだから特殊な値を代入して何かしてみるべき (極めて一般的な手法).例えば として (これは自然な「特殊な値」), だけど,これすら各 について手早くのは難しそうなうえに得られる情報量が少ない (普通の感想).得られる情報量を多くしようとして指数の底を とか とかじゃないようにしても綺麗になる気配はない (たぶん普通の美的感覚).ということで,代わりに を考えよう (これは,お気持ちはわからなくはないけど,かなり賢いと思う).左辺は Hadamard 変換の線形性を使えるうれしい形をしていて, を一度変換すれば各 について求まる.
同様に と が求まることがわかった.あとどんな関係があれば とかを特定できるか?というと,長さ の Hadamard 変換っぽい見た目をしているので (Hadamard 変換の問題を解いているのだから Hadamard 変換っぽい見た目には気づく), とかそういうやつがほしい.それは とかで,そんなのが求まるかというと,よく見ると なのでうれしい (冷静さが必要).これでできたのでまとめると,
解法
- のそれぞれを Hadamard 変換する.
- 各 に対して, 項目を集めて長さ の列にして Hadamard 逆変換すると, の各指数が得られるので,計算する.
- というのを並べて,Hadamard 逆変換すると答え.
コメント
項しかないというのの は小さいことしか本質ではなくて, 項だったら 時間とかでできますね.
思考の整理のために書いてみたのですが,賢いところが一箇所な割にはすごいことができていて,不思議な感じが残りました.
Xmas Contest 2018
Xmas Contest 2018 にご参加いただいた皆様,どうもありがとうございました!
2015, 2016, 2017 年は元気にしていなくて開催できなかったのですが,その間引き継いでくれていた japlj さんと snuke さんと共に今年は運営しました.とっつきやすい良問を作ってもらったり (A, F, G),雑に提案したのをちゃんと解いてもらったり,クリスマスコンテストっぽくない問題をちゃんと却下してくれたり,いろいろやってもらえて助かりました.
わたしが原案を出した問題の解説をこのブログに載せておきました.変なとこがあったら教えてください.数式多めなので環境によっては見づらいかもしれませんごめんなさい.
Xmas Contest 2018 J: Japanese Exponentation 解説
https://atcoder.jp/contests/xmascon18/tasks/xmascon18_j
問題概要
四の三の二乗乗
みたいなのを で計算せよ.
解法
UTF-8 の文字列を処理する方法は,皆さんお使いのプログラミング言語ごとに調べてください.
冪乗を で計算する方法を考えます.「 のとき 」は正しいですが,「 のとき 」は正しくないので,指数は勝手に をとってはいけません.
とはいえ, での は必ずどこかから周期的になります.最初から周期に入っているとは限りません.例えば のときは となり, から長さ の周期に入ります.どこからどんな長さの周期に入るかについては,以下の事実がよく知られており (補足参照),この問題ではこれで十分です:
- なら, は既に周期に入っている.
- 周期の長さは の約数である.ただし は Euler の φ 関数.
というわけで,指数はおおよそは でもっておけばいいですが,小さい値,雑に 未満くらいは特別に扱う必要があります.実装上は,例えば次のいずれかのような方針がわかりやすいと思います:
- をとる代わりに, 以上の整数は に収めるようにする ( を にする).
- 整数 の計算結果として,) の組をもつ.
以上をふまえると,構文解析パート (再帰下降) を合わせて解答は次のようになります.
Result expr(m): // Result 型は上記のように特殊な mod のとり方をした整数 Result a := number(m) // 整数を読む while 次の文字が "の": "の" を読む Result b := expr(φ(m)) a := a^b // 繰り返し二乗法などで計算 "乗" を読む return a
なお, は 回で になるので,同じ の計算を複数回しないようにすれば実行時間は大丈夫です.
補足
での の様子について,もうちょっとちゃんとした話をします.
中国剰余定理より, としては素冪 だけ考えればよいです.素冪ごとに考えた後で,周期に入る場所は をとればいいし,周期の長さ (の倍数) は最小公倍数をとればいいです.
( は非負整数, は で割れない) と書くと, のとき の部分は累乗していくと途中からずっと になってしまい,これが周期の前の部分を作っている要因です.高々 乗で になるので,周期に入るまでの長さは 以下です.一方 の部分だけ見ると最初から周期に入っていて,その周期は
- かつ のとき
- その他のとき
の約数です.さらに,実際にこれらの周期をとる が存在します (原始根の存在定理など).
ここまで考察すると,この問題で必要な は だけで済むことがわかります.
コメント
この問題は,本当に問題文のストーリー通りの流れで作りました.「 の 乗」の構文は,
になっていて面白いです.
マルチバイト文字は,こういうコンテストだからこその出題という感じですね.いろいろ調べていたら 六
にだけ互換文字があるとかいう知識が増えてしまいました.
数学パートは,「普段なんとなくで をとっていませんか?」というメッセージ (?) です.
Xmas Contest 2018 I: Interesting Equation 解説
https://atcoder.jp/contests/xmascon18/tasks/xmascon18_i
問題概要
実数 が与えられるので, がだいたい になるような整数 を求めよ.
解法 ?
なる解の存在が保証されているので,その範囲の をすべて調べられれば答えが見つかります.
もちろんそれでは遅すぎるので,半分全列挙のようなことを行いたいです. の小数部分たち, の小数部分たちをそれぞれ列挙すると,ソートして尺取法などを行うことによって答えを探せます.これでも片方は 通りほど列挙しなければならないので厳しいですが,何回か提出して の範囲を適当に制限するなどの方法で正解することができるかもしれません (実際,コンテスト中にこのような解法が何件か正解していました).
解法 1
より均等に分けた半分全列挙を行うことができます.例えば (,) と表すことができ, の小数部分たち, の小数部分たちを列挙します.するとどちらも 程度のサイズとなり,十分高速となります.
チーム aadeeggimrsstuw がこの解法で正解していました.
解法 2
を十分大きい値として, の 本のベクトル
を考えます ( は に最も近い整数とします).これらの整数係数線型結合であって長さが十分短いものを見つけられれば,それが答えになります:整数 に対し の長さが短いとき, は小さく, は くらいなのでだいたい ,という気持ちです.
「整数係数線型結合で長さが十分小さいもの」を見つける方法として,LLL Algorithm が知られています.詳しい説明は web にいろいろな資料があるので,ざっくりだけ紹介します.
集合 (格子と呼ばれます) を変えないように を変形していきます.変形の操作は次の 種類からなります:
- いい感じの条件を満たすように を並べ替える.
- に Gram-Schmidt の直交化を行ったものを とする. に対し, を で置き換える.
これをいい感じの順番で行うのが LLL Algorithm で,一般の 次元でも多項式時間で最適解の 倍の長さのベクトルが得られるそうです.すごいですね.一応なぜ直交化したいかの気持ちを説明すると, は生成する格子にしかよらず (格子の体積),これは基底が直交していれば長さの積,ななめっていれば長さの積より小さくなっていくので,体積一定では直交に近いほうが長さが短い,という感じです.
この問題では,がんばって評価をすると, ととれば制約下で正解が保証できることが示せます (ごちゃごちゃしてしんどいだけなので省略します).演算は double 等でも大丈夫だと思いますが,多倍長有理数で時間に余裕を持ちつつ正確に行うこともできます.
omeometo さんの解法は,LLL Algorithm の代わりに, を で置き換えるというのをランダムな を選んでたくさんやっていました.ベクトルが短くなっていく感じはほぼ同じなので,十分な回数回していれば落ちなさそうです.
コメント
コンテスト開始直後,全 ではないという条件が抜けていました.そういうつもりじゃなかったんです,でもクリスマスコンテストならそういうのありえますよね…….ごめんなさい.
想定解は解法 で,無理問だけど強引にも通せるかも?くらいに思いながら出題しました.予想より正解者数が多かったです.特に解法 は全く気付いていなかったのでなるほどという感じでした.
問題文冒頭はさすがにやりすぎですが, 次式の根で を近似すると なんてのが得られたり,LLL Algorithm でいろいろ遊んでみると楽しかったです.
Xmas Contest 2018 H: Hello, Xmas Contest 2018 解説
https://atcoder.jp/contests/xmascon18/tasks/xmascon18_h
問題概要
文字列 が与えられる.グリッドの一部に A
-Z
または *
を書いて,
- 各行の最初の非空白文字を順に繋げて
*
を除いた文字列が - 各列の最初の非空白文字を順に繋げて
*
を除いた文字列が
となるようにする.最低何文字書く必要があるか? (入出力例の図を見るのがわかりやすいです)
解法
ある文字 が に 回, に 回現れたとすると,文字 は少なくとも 個書かなければいけません.これを A
-Z
について足すことで答えの下界が得られます.
この下界はだいたい達成できそうな気がします:
|AAACCB -+------ A|A..... A|.AA... B|.....B C|...CC. B|......
具体的には, と の両方に現れる文字は問題なく配置できます.片方にしか現れない文字がある場合は,
|UNAGI -+----- U|UN... S|S.... A|..A.. G|...G. I|....I
|BAD -+--- A|.AD B|B.. C|C..
のように 行目の文字や 列目の文字で隠してしまえばよいです.隠せないのは,
|AC -+-- W|.. A|AC
のように 行目の文字が に現れない場合,あるいは 列目の文字が に現れない場合,のみです.そのような場合は *
を 個以上書く必要があり,逆に *
を 個左上に書いてしまえば隠したい文字を隠せます (看板を作ることが不可能なケースはありません).
まとめると,
A
-Z
のそれぞれについて, に現れる個数と に現れる個数の をとって足し,- の先頭が に含まれない,あるいは, の先頭が に含まれない,という場合だけ を足す
と答えになります.
コメント
最初は,色のついた積み木を積んだときの見取り図が 方向から与えられる,という設定で解こうとしていて,しかし高さ 以上のときわからなかったので高さ にしたら,無意識に昨年の問題と同じような設定になっていました.
制約は,解法を絞らせないために敢えてゆるくしました.
Xmas Contest 2018 E: Exclusive☆OR 解説
https://atcoder.jp/contests/xmascon18/tasks/xmascon18_e
問題概要
個のブール変数から 個とった XOR たちを,AND と OR と NOT を使って作る.NOT の使用回数を最小化せよ.
N = 1 のとき
何もしなければ正解です.
N = 2 のとき
なので, に NOT を使うと 回でできます.NOT なしでは と しか作れないので, 回ではできません.
N = 3 のとき
NOT 回でできます.下からの評価 ( 回ではできない) は後ほど.
の場合はこちらで手で遊べる.
と書いてあるやつで遊んでみると解けるかもしれません.正解できる NOT 対象はいくつかあるのですが,次の方法が一般の での解法に繋がります:
は「 のうち true のものの個数が のいずれかである」かどうかを表すブール変数になっています.この変数に着目することが以下の解法での鍵となってきます.
N - 1 回解法
次の ステップでできます:
- を求める.これは AND と OR だけでできる.
- を求める. である.ここで 回の NOT を使っている.
- を求める.まず, を「 と 以外のうち true が 個以上」かどうかとする.これは AND と OR だけで求まる.すると,以下が成り立つ:
最後の式が何を意味しているかというと,「 と のうちには true が 個以上」かつ「 と 以外には true が 個以上」かつ「全体では true がちょうど 個」,というのを について OR をとっていますが, なので「以上」が消えて,「 と のうちには true がちょうど 個」,すなわち がもれなく求められている,ということになります.
log N 回解法
上の解法のステップ は実は 回の NOT でできてしまいます. のときの例を示すとこんな感じ:
一般には, に対して,「下から ビット目が である数に を足したもの」たちが の中身に入るような変数に NOT をすると上手くいきます.すごい.
行数制限
ここまで NOT の回数だけを気にしていましたが,この問題では AND, OR, NOT を合わせて 回以下でなければいけないのでした.ステップ とステップ で「true が 個以上」みたいなのを求めるのを愚直にやると について指数回かかってしまいます ( くらいまで正解できて, 点です).これは,DP で の計算でできます:
for i = 0 to N - 1: for x = N - 1 to 1: f(x + 1, ..., N) := f(x + 1, ..., N) OR (f(x, ..., N) AND b_i) f(1, ..., N) := f(1, ..., N) OR b_i
ステップ のほうでは 回 ( たちから 個除いて) これをやるので 回の計算になります.実はこれを にすることもできますが省略します (満点には必要ないです).これで無事に 行に収まるようにできました.
下からの評価
NOT の最小使用回数は です.これ未満ではできないことを示しておきます.
NOT の使用回数が でできるプログラム が存在したとします. の入力に の 通りを入れたとき, なので鳩ノ巣原理より,どれか パターンでは 回の NOT の計算結果が全部一致するはずなのです.それを と () のときとします.
このとき,以下のようなプログラム が作れてしまいます:
- の入力は 変数である.入力 に対して, に入力 を与える.
- の計算途中において, 箇所のNOT を使う部分は,上で計算結果が一致したという値の定数に置き換える.
- の出力 をとってきて の出力とする.
すると の出力は ですが, は AND と OR しか使っていないので NOT ができてしまうのは矛盾です.
コメント
コンテスト開始後はしばらくジャッジが正常に動いておらず申し訳ありませんでした.
満点までの道のりが壮大な感じで,難しい問題だったと思います.でもなんかすごいですよねこれ.
作題のきっかけは,「3-not problem」 (2 NOTs problem だったり呼称は安定していないっぽい) という一部界隈では有名らしい問題を知ったことです. で, を NOT 2 回で作ろうというもの.一般の では最小 回です. たちがあれば XOR は作れるのですが, を考えたらもう少しうまくできるのではと思い, を全探索していろいろ気づいた,という流れでありました.
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 数学センスを問う問題にしてみました.不思議な問題ですね.