06/19(月)
午後3時起床。ABC305の総合1位・学生1位の商品でアマギフ75000円が届いていた。かなり現実味を帯びてきた残高7桁は一度見てみたいが、そのあとは使用期限に注意してちゃんと消費していかねばならない。
そのまま布団でスマホを弄っていたら購買に行く時間がなくなってしまった。適当なタイミングで布団から脱出し、午後4時半からインターン先定例会に参加した。
進捗報告はまあ良しなに。勉強会は大規模言語モデルに対するプロンプトハッキングの話だった。多種多様な攻撃の例ももちろん興味深かったが、一番衝撃を受けたのはbase64でエンコードした文章をデコードさせることで任意の文章を出力させるというものだった。そもそもbase64を扱えるというのが驚き。エンコード後の文字列をググっても何もヒットしなかったから、丸ごと覚えているというわけではなさそうだった。本当にbase64を「読み書き」しているのである。
学食で夕食を摂った後はずっと週記を書いていた。午後11時半に投稿。集中を切らしてハーメルンを開き、見つけた作品「今日も楽しく安価だ!」を一気読みした。
やっぱり安価系は苦手らしい。主人公の行動が主人公以外によって決められるという不自由さがどうしても好きになれなかった。ただそれはそれとして、この作品は主人公がとにかく強いという点が好みだったためぐいぐい読み進めることができた。安価の要素があっても面白い作品は面白い、ということで。
先週の週記で穴あきになっていた箇所のうち、Universal Cup以外の部分を書き上げた。その後シャワーを浴びて日記を書き午前9時就寝。
06/20(火)
午後3時過ぎ起床。
先生に誘われた確率論のセミナーに出席した。午後3時半開始のところ10分ほど遅れて教室に到着し、それから午後5時までずっと聞いていたものの、何一つ分からなかった。知らない分野の話題を英語で話されると本当に無理。資料もなく真に何も得られなかった。
生協に寄ってラノベを受け取り夕食を摂って帰宅。先週土曜日に参加したDMOJのコンテストが終了していた。
DMOPC '22 June Contest - DMOJ: Modern Online Judge
1問目は使うのは1と2だけでよさそう。どちらかの使う個数を全探索する。
2問目は項目から始まる連続部分列個の符号が全部一致するようにした。まずをできるだけ半々になるよう分ける。降順に見ながら貪欲に割り振っても最適になるようだ。この分け方と一致するように対する符号を決め、の順にその符号が達成できるギリギリの値を置いていった。絶対値に関する条件も満たせたので提出、AC。
3問目は十分大きな値に変化させることでそれより前と後で大小関係が逆転しないようにできる。なので変化させた値の直前でを分割したとき、それぞれで累積XORが広義単調増加になればよい。分割は貪欲に行えるので、1回目の分割までは実際に累積XORを見て取る。
その後は分割位置を先にずらしながら矛盾するところを探す。であることとの最上位bitが(あれば)で立っていないことは同値。つまりそうなるように直前に変化させた要素を確定させなければならず、ここで矛盾が発生しうる。
4問目も5問目も解けないまま時間切れ。300点で22位、レートは2987→2909(-78)となった。さすがに悔しいので解説を見つつupsolveした。
4問目は部屋を鏡写しに拡張してボールの移動を直線だと思うテク。これでスタート地点に戻るまでの時間を考えることはできていたが、同じ壁に2度タッチする場合が分かっていなかった。これが起こるのはコーナーで跳ね返ってから秒後、つまり次に壁に当たるタイミングらしい。言われてみれば……という感じ。
秒移動した場合、スタート地点に戻る条件はである。図を描くとのような点がありそうに見えるが、実はここに行く場合必ずコーナーを経由するので無視してよい。コーナーに当たる条件はとなる。前者は単なるLCM、後者は拡張ユークリッドの互除法で解ける。
ただし後者については注意が必要。なるを求めるのになるを求めた後倍するが、その後で割った余りを取らなければ最小にはならない。ランダムケースを試して気づくまでここでもやられ続けていた。中国剰余定理は思いつかなかった。
5問目は、最初にできるだけ多くドミノを置いた後、隣接するまだ埋めていないマスと合わせてトリオミノにすればよいと思っていた。これは二部マッチング2回で計算できる。ところが合わない。しばらく考えていたら以下のようなケースでは最初のドミノの置き方が悪いとうまくいかないことに気づいた。
##. ### .#.
そのほかグリッドから二部グラフを作って長さ1または2のパスで全頂点をdisjointに覆えればOKということも考えたが、実現できなかった。終盤は二部マッチングの計算時に辺を見る順番をランダムにして何度か投げていたものの、どうしても突破できないテストケースがあってダメだった。
最初から短いパスで覆うのは計算できないが、全頂点の次数が1か2になるように部分グラフを選び、連結成分それぞれを改めて分割するとよいらしい。これも言われてみればそうだが自力ではなかなか思いつけないだろう。二部グラフなので次数の制限は最小流量付き最大流で表現できる。
コンテスト中読みもしなかった6問目は、5問目に関する構築だった。5問目で自分が書いていたWAコードを使い縦横5マスで全探索したら見事に見つかって残念。ちゃんと目を通せばよかった。
先週日曜日に参加した三つのコンテストの動画を投稿した。
【競技プログラミング】Codeforces Round #879 (Div. 2)【実況】 - YouTube
【競技プログラミング】ARC162【実況】 - YouTube
【競技プログラミング】Codeforces Round #880 (Div. 1)【実況】 - YouTube
今日出たコンテストのうち内部コンテスト以外の三つは動画を撮っていたものの、DMOJ参加時のコードや入力サンプルが映り込んでしまった。編集で消せばよいのだが、安全のため来週火曜日のDMOJ終了まで塩漬けにしておくことにした。
週記(2023/06/12-2023/06/18) - kotatsugameの日記
しばらく日記を書いて、午後11時半からCR #881 div.3に出た。
Dashboard - Codeforces Round 881 (Div. 3) - Codeforces
Aはcostのことを要素に+または-の符号を割り当てて足し合わせた値だと思うことができるので、大きいほうから半分を+、もう半分を-とするのがよい。が奇数の時は真ん中の値を無視する。
Bは操作する区間がdisjointだとしてよい。負の数を見つけたらそこから次に正の数が出るまでひっくり返す、という操作が最適。これで0が適切に無視できている。
Cはセグ木のindexingと同じ。やるだけ。Dは各頂点について部分木の葉の数を数えておき、掛け合わせたものが答えになる。Eは二分探索。
Fは重みがなので連続的に変化すると思える。つまりクエリで指定された列について、その連続部分列における重みの和の最大値・最小値を求め、がその間にあるか判定すればよい。F1はが根に固定されているため、木を構築しながらすべてのに対してこの値を管理できる。
ところでこの最大値・最小値の計算はセグ木に乗るから、F2は木をあらかじめ構築しHLDを使うことで解ける。モノイドの積が可換でない点に注意。が二つ付くし計算に必要な値が多く定数倍も悪いからちょっと心配していたが爆速だった。
全完、5位。F2の実装では最初メモリ使用量の削減のためshortを使っていたが、値が収まらないことに気づきintで出しなおした。結果だけ言ってしまえばopen hacking phaseでHackされなかった。ラッキー。Hackを避けるため動画は次の日に投稿した。
また日記を書いていたが、眠すぎて全然進まない。耐えかねて午前3時過ぎに寝た。
06/21(水)
数度の中途覚醒を挟みつつ午後8時まで寝ていた。睡眠負債を解消できた気持ちになった。
昨日のCF div.3のopen hacking phaseが終了していたので、動画を公開した。その後少し日記を書いて眠気を振り払った後、午後11時くらいからTCB59に取り組んだ。
https://techful-programming.com/user/event/4419
1問目はよい。2問目は適当な範囲、例えばを全探索。3問目はで全探索。4問目は2点固定して、残りの点がその2点を結ぶ直線上にあることをチェックした。5問目はと変形できるので、たちの約数を列挙してカウントしておけば数えられる。
6問目は大変。とする。長さの文字列を数えると、では周期が関係ないので通り、では周期なので通り、では一致する箇所が微妙に増えて実験により通り、あとは周期1なので通りとなった。これを頑張って足し合わせる。15分かかって-3pt。
7問目は人の快適さが以上であるような並べ方を考えた。人の前人が人なので通りとなる。Wolfram|Alphaににおける和を聞いたら閉じた形になった。それをで足し合わせるとに対する答えになる。
8問目も大変だった。6問目のときの観察から、としてにおける答えが求められればよい。例えばのとき、0文字目と文字目つまり文字目が一致する。のときは追加で1文字目と文字目も。同様にして、に対し文字目と文字目が一致するようになる。
すると問題がに書き換えられる。ただしこれでとなる場合の答えはとする。がユークリッドの互除法のように変化するため、この再帰は十分高速。40分かかって-22ptとなった。
9問目はさらに大変だった。を許す場合の凸包を求める問題は見たことがある。点を追加するたび凸包がだけ伸びるが、伸びるとは凸包の辺をぐるっと一周して得られるベクトルにが追加されるのと同じであるから、これらのベクトルを集めて偏角ソートすると最終的な凸包の辺が反時計回りに得られる。あとは適当に1点、例えば座標が最大である点のうち座標最小のものを構成して、そこから一周することで具体的な点たちを計算できる。
ここからつまり原点を適切に取り除かねばならない。単に取り除くだけではダメで、そうして凸包から1点消えるとき減った三角形領域内に他の点が存在するケースがある。
凸包の頂点に原点が含まれるなら、与えられた点はすべて偏角180度未満の区間に収まっている。このとき「どんな2点の和もその2点を結ぶ直線を挟んで原点と反対側にある」ということが任意の個数に拡張できて、たちのうち減った三角形領域をカバーするのに考えるべき点が最初に与えられた点たちだけだと言える。
まとめると、上に述べた方法でを許した場合の凸包の頂点を列挙し、そこから原点を削除して代わりに入力で与えられた点を全部追加し、改めて求めた凸包が答えである。4WAと59分かかって-78pt。
10問目はすごい問題。非自明なステップをいくつも踏む必要があって、解けた時の快感はとんでもないものだった。
問題を整理すると、求めるものは「宝石の魔力の総積(に適切に符号を付けたもの)」の「すべての置き方を渡る和」、つまりである。ここで宝石の魔力は働きかけの重みの和だからと書けて、宝石の魔力の積と働きかけの和を入れ替えることで「宝石の魔力の総積」を「働きかけの重みの積」の「働きかけを各につき一つずつ選ぶ方法を渡る和」とできる。つまり。
二つのを入れ替えてみる。つまり働きかけを各について選び、に選んだ働きかけが存在するような置き方の分だけ係数をつけて足し合わせてみる。
実は置き方はそれほど多くない。大杯に入る宝石の集合を決め打つと、そこからという辺に沿って距離を求めることでほかの宝石がどの小杯に入るか決まるからだ。というfunctional graphは各連結成分に一つループを持つが、このループのうち少なくとも1頂点は大杯に入らなければならない。逆にそれさえ満たせば置き方がちょうど一意に定まる。
例えば連結成分が一つだとして、ループ上の頂点が個、それ以外の頂点が個あったとしよう。このとき置き方による係数は魔力の符号も込めてとなる。つまりなら係数は0であり、無視してよい。は必ず正なのでなら-1となる。
連結成分が複数あった場合はこれの積になる。つまり掛ける係数は、functional graphがループに含まれない頂点を持つなら0、持たないなら連結成分数をとしてとなる。ちなみに、ここまで来ても重みのせいでまだ指数時間から抜け出せていない。かなり心が折れそうだった。
ここで二つの事実を思い出す。まず、functional graphがループのみから構成されることとが順列であることは同値。次に、このとき上で定めたはと一致する。ここでは置換の符号を表す。
以上より、求める値はと分かった。これはを除いて成分がであるような行列の行列式と一致する。このような対称性のある行列を「Circulant Matrix」と言い、検索すると行列式の公式が出てきた。
Determinant of a General Circulant Matrix | Problems in Mathematics
を1の乗根、として、行列式はと表せるらしい。ここまでくれば見覚えがあるどころの話ではなく、を離散フーリエ変換して積を取れば求まる。が2べきである制約が見事に回収された。99分かかって-56pt。
4時間弱かかって終えたのは午前3時だった。そこから3時間日記を書いた後インターンの作業をした。
不要ファイルの削除を行うためコードの依存関係を調べた。pydeps
を使ったら不要なまでに深い依存関係まで表示されてしまって、必要なところだけ抜き出すのもうまくいかず、結局手作業で1ファイル1ファイル見ていった。
またドキュメント整備のためコードを読んでいるときにバグを発見した。意気揚々と報告したがコミット履歴から過去の自分が埋めたバグだと指摘されて愕然。ほとんど同じ行が2か所に出現していて、書き間違えたままコピペしてしまったのを、当時片方だけ指摘されたのだった。
購買が開店したくらいで切り上げ、パン類を買い込んできた。一部を昼食とした後正午くらいに就寝。
06/22(木)
午後5時前に起床。すぐ1on1に臨んだ。
昨日調べたことをもとに不要ファイルを削除するプルリクを出してマージしてもらったり、バグ修正をしたりした。またpydeps
が使いにくいという話をして、1on1中に二人でいろいろ試した結果表示したくないファイルを丁寧に指定することで必要な範囲だけ取り出した画像を生成することに成功した。結構時間をかけたので1on1中にやるべきことではなかったかもしれない。
最近やっていたコードの整備は後片付け的なものであり、これですべて終了。自分の次のタスクは全く別のところの話になる。1年弱の間1on1をしてくださった感謝を伝え、解散した。
今日は自分がインターンを始めたころに1on1をしてくださった、日記ではずっとメンターと書いていた方と、自分が次に取り組むタスクについての話をした。
週記(2023/06/05-2023/06/11) - kotatsugameの日記
今日は午後10時からSRMがあるという話だったが、確認すると明日の午前10時からだった。このずれは公式サイトが開始時刻の午前と午後を間違えていたからで、それを見たclist.byにも違う時間で入ってしまったというわけ。終了時刻は正しかったため、注意深く観察すれば14時間コンテストになっていて何かおかしいと気づけたらしい。
来月刊行される新刊をチェックした。今回は23冊注文。米澤穂信さんの新作が出るらしい。
来週月曜日のインターン先勉強会の発表に向けて調べものをしたり、布団でラノベを読んだりして過ごした。午前4時就寝。
06/23(金)
午前9時半起床。午前10時からSRM847に出た。
https://community.topcoder.com/stat?c=round_overview&er=5&rd=19638
Easyはターン目までに逃げることのできる馬を頭としての最小値が答え。を求めるためには各マスから囲いの外まで何手かかるか計算する必要がある。メモ化再帰を書いたらstack overflowして途方に暮れたが、実は上下左右どれかの方向に距離2ずつ進んでいくことだけ考えるので良い。よって単純な割り算で出る。
Medはよりとした列を広義単調減少にすればよい。最大で何個そのまま残せるか計算することになって、これはLISである。
Hardはを全探索。の候補はの約数の2乗個ある。の候補はかつより個である。約数の個数とのどちらも時間で前計算できる。
30分で全完。しかし見直しをしていると、Easyにおけるの計算が「ちょうどターン目に逃げることのできる馬の数」となっていることに気づいた。サンプルが合ってしまったのだからもしかしたらこれでも答えは変わらないのでは!?と願ってチェックしたが、当然ながら盛大に間違っている。泣く泣くリサブした。
チャレンジフェーズではEasyで自分と同じミスをしている人を探し、一人落とすことに成功した。これで少し点数が上がったのと、あとは自分の上でシステス落ちが少し出たため、順位は4位。しかしレートは2824→2831(+7)としょぼい変化しかしてくれなかった。
布団に戻ってラノベ。「異世界でチート能力を手にした俺は、現実世界をも無双する」14巻を読了した。新しく大量の設定が生え、いくつかはこの巻の中で消化されいくつかは次巻への引きとして残された。話がポンポン進んでいくので読みやすくはある。
午後3時前に外出。まず大戸屋で食事した。記憶している限りでは初めて入ったが、青葉通り一番町駅の近くにあってなかなか行きやすい。健康のためにこれからはここをリピートするようにしたいと考えた。
— こたつがめ (@kotatsugame_t) 2023年6月23日
それからゲーセンで遊んだ。今日もアップデートで増えた新曲を埋めたが、それよりはアイマスとのコラボイベントのマップを走る日だった。205マス×9というとんでもない状態になっている。イベント終了まで時間的余裕がない。イベントアイテムはできるだけ全回収したいのだ。
無慈悲な集金マシーン pic.twitter.com/nQ7pzxixGE
— こたつがめ (@kotatsugame_t) 2023年6月23日
午後8時半ごろ退店。ブックオフに寄りつつ帰宅し、午後9時20分にほんの少し遅刻してyukicoder 394に出た。
yukicoder contest 394 - yukicoder
Aはわからなかったので1手目を全探索して2手目で区別できるかチェックした。当然だが1手目の結果に応じて2手目で聞くは変えなければならない。
Bは大小関係を固定して……など考えそうになったが、冷静になるとを全探索してとすればよい。。
Cはすべてのについて一気に解いた。各について、が大きいなら個しか該当するが存在しないため愚直にカウント、が小さいならimos法で後からまとめて処理する。閾値はくらいにしておけばよい。
Dは各の寄与を考えたが重複を取り除くのが結構面倒だった。向きを込めた辺について、これを含むパスに対するの寄与を考える。パスの始点はから見たの子孫の数だけ候補があって、これはそのまま係数になる。パスの終点はが現れる桁に関わり、その係数は全方位木dpで計算できる。あとはパスの終点を考慮すればよく、シンプルにである。
Eは面倒。Suffix Array+LCPを構築しておく。まずをSuffix Array上で最も先頭に近いものとして取り直す。つまり、から始まるsuffixとその一つ前に並んだsuffixのLCPが未満になるようにする。こうするとより前に並んだについては必ず条件を満たす。この部分の数え上げは単にの和を取ればよい。
以降のについては、切り出す文字列の長さが未満かつとのLCP以下になっていることが条件。つまりから後ろに見ていったときのLCPの累積MINを考えることになるので、をSuffix Arrayにおける降順に舐めてLCPの累積MINをstackで管理しつつ、長さに対するの個数を区間ADD区間SUMの遅延セグ木で持った。
Fは何もわからず、6位。
ゲーセンで撮った手元を2本ツイートした。「To:Be Continued」は今回かなりうまくいったが、相変わらずラストが何もわかっていないため崩壊。どうせすぐ疲れて連奏できなくなるのだから座学する気も起きない。
LAMIA 6-2 手元 pic.twitter.com/1MS913DqoE
— こたつがめ (@kotatsugame_t) 2023年6月23日
しばらく日記を書いた後ラノベを読んで、午前5時半くらいに就寝。
06/24(土)
午前9時から4時間ちょっと目を覚ましてハーメルンを読んでいた。二度寝後次に起きたのは午後7時。
ICPC模擬国内予選が終了していた。先週内部コンテストとして参加していたので、今ここに感想を書いておく。
午後2時から3時間、模擬国内予選の内部コンテストに出ていた。
週記(2023/06/12-2023/06/18) - kotatsugameの日記
Aはよい。Bは二分探索の上限を「運用して得られる増分が以上」ということでにしており1WA。最初に引かれるのでにしなければならなかった。
Cはが大きいもの二つしか遊ばなくていいんじゃないかと思い試してみたら通った。ところが何を思ったか11111121212...
という遊び方をしており、後でテストケースが更新された際に落ちていた。逆になぜ一度は通ってしまったのか……。
Dは内部コンテストから問題が少し変わっているのでよく知らない。ただFPSのべき乗で表現できることは同じで、自分は元の問題でも最初にそれを書いていた。二分累乗法をするのではなく、あらかじめ十分な長さでDFTした列を持っておき、テストケースごとに各点をべき乗してからIDFTすると定数倍が結構良いだろう。
Eは点と直線の距離ならの最小化で、extgcdはが最小の値を返してくれるからそれだけで解けそうに見える。実際は線分なので微妙に異なるはずだが、のうちサンプルが合う方を出力するようにしてとにかくサンプルを合わせたら通ってしまった。よくわかっていない。
Fは2次元BITをその場で書いて二分探索、。爆速だった。
Gは取り組んだものの解けなかった。映画を見ていない時間を最小化しようとすると、映画の上映終了と別の映画の上映開始をうまくマッチングする問題になる。各時刻の入次数と出次数を数えて貪欲に繋いでみたがWAだった。解説で言う連結性に違反してしまったようだ。Hは読んですらいない。
またハーメルンを読んで過ごし、午後9時からABC307に出た。
A、Bはよい。Cでどん詰まりした。実装を頑張るだけの問題だろうと思い、コーナーケースを踏まないことを優先して30x30の盤面の上での位置を全探索する方針を考えたが、これは306通りにチェックの時間もかかるので間に合わない。まさか計算量改善を要求されるとは思わず思考が停止してしまい、を固定しては相対位置で全探索すればよいということに気づくまで時間がかかった。
Dはstackとそこに積まれている開き括弧の数を管理。ところが管理に失敗して1ペナ生やしてしまった。
Eは頂点のサイクルの彩色を数え上げる問題。サイクルから1辺消したときは通りで、そこから消した1辺の両端点の色が一致するケースとして頂点のサイクルの彩色を引けばよい。以下同様にしてにまで帰着したら終わり。この方法は1辺削除したグラフにおける場合の数から1辺縮約したグラフにおける場合の数を引いていて、彩色多項式の求め方をなぞっている。
Fはちょっと詰まった。なら感染させられる距離の残りを持つdijkstraで解ける。これを拡張して、今の日付も一緒に持つことにしたら解けた。比較関数は日付を先に見るものとする。辺を通る際は、距離が足りていればその分を引き、足りなければ足りる日を探す。探すのは区間MAXを取得できるセグ木上で二分探索すればよい。
Gは操作によって全体の和が変わらない。よって各要素がもしくはとなるようにする場合が必要で、高々2通りのについて計算すればよい。正確には2通りあるのはだけ使う場合とだけ使う場合なので全く同じものだが、いずれにせよ定数倍の問題なので気にしないことにした。
各要素についてとのどちらにするか決めると、操作は先頭から貪欲に行うのが最適となる。このとき各要素にはそれより前の要素を揃えた時のしわ寄せが来るので、それを加味しながら操作回数を考えればよい。つまり、を変化させた後の和がだとすると、その時はだけ増えているということ。
を求めるにはこれまでいくつにしたかがわかればよいから、とその情報を持つことでdpできる。最終的には全体でを個使った場合の操作回数の最小値を求めればよい。
Exはずらしながらのマッチングなので畳み込みを使うのだろうとすぐわかって、あとは具体的にどうするか。の後ろに文字の.
を追加すると、の文字目が電光掲示板の文字目に表示されるのがの時だと表せる。つまりなるの個数をに対してカウントし、それがの_
でない文字の数と一致したものを数え上げればよい。
自分は53種類の文字それぞれに対してとを01列に変換し畳み込むことでカウントした。制約が微妙に大きいがまあ間に合うだろうと出したら3285ms。さすがに最大ケースも試さなかったのは危ない行為だったなと感じた。
1ペナ全完で8位。上二人とは1分も差がないため、つくづくDのペナが悔やまれる。Exはワイルドカードありマッチングとして昔やったことがあるのに頭から出てこなくて残念。通ったからよかったものの……。
?(任意の1文字)を含む文字列のマッチングがFFTでできるという話を覚えていたので、試した。
週記(2020/11/30-2020/12/06) - kotatsugameの日記
コードゴルフは少しだけ。Aはbashの28Bがあって、Rakuで書いても28Bだった。Eはdcで縮めてみたが負け。他は手付かず。
午後11時からCF combinedに出た。
Dashboard - CodeTON Round 5 (Div. 1 + Div. 2, Rated, Prizes!) - Codeforces
書く:CF
- LGM
CodeTON Round 5
— こたつがめ (@kotatsugame_t) 2023年6月24日
oooooooo- 9th
2870 -> 3003 (+133) highest
Legendary Grandmasterになりました pic.twitter.com/hIGHuRs9sN
動画を投稿した後は昼前までずっとハーメルンに熱中していた。日記を書き、正午を過ぎてから就寝。AHCまでに起きるため30分おきに目覚ましを設定しておいた。
06/25(日)
午後3時前に気合いで起床。AHC021に参加した。
TOYOTA Programming Contest 2023 Summer(AtCoder Heuristic Contest 021) - AtCoder
前回の経験を踏まえ、今日は最初の1時間は絶対に貪欲しかしないと決めていた。強い貪欲なんてなんぼあってもいいですからね。
最初から焼きなましをするのは良くなかった。ちゃんと貪欲→山登り→焼きなましというステップを踏み、それぞれで工夫を入れるべき。
週記(2023/06/05-2023/06/11) - kotatsugameの日記
適当に書いて最初の提出が20分時点。しかしすでに上位と差がついている。いろいろ試してみたが自分の順位は落ちていく一方だった。よく見ると13426585点を出している人が何人もいる。まったく同じスコアが何度も出されるということはランダム性のない貪欲によるもので、しかも序盤から出ているのだからかなり簡単な方針のはず。これを再現するのを最初の1時間の目標にした。
解法ガチャを回し続けた結果、1時間4分時点の提出でようやく再現することに成功した。小さな数のボールから順に、直上のボールとのペアが条件に違反している間上に持ち上げていくというもの。この時直上のボールは二つあるので書かれている数の大きいほうを選ぶ。
この解を検討していて気付いたのだが、段目にのボールが並んだ状態でなくても条件に違反するボールのペアを0個にできるらしい。問題の誤読……というのも少し違うか。嘘の性質を示してしまっていた。だから序盤の貪欲がどれも振るわなかったのだと納得。ちなみに問題ページのGIF画像をよく見ることでも気づけたようだ。
また同時にこの貪欲がかなり強いことを実感した。ここからどう改善すればよいかアイディアが全く出てこない。操作の途中で何かするのは難しそうだから、貪欲を発動する前を弄ることにした。ランダムな操作を入れて山登り法を行うと思ったより改善されて、7万点アップの13498450点が出た。
もう何もわからないので焼きなましを初めてしまうことにした。忘れていた操作の削除を近傍に加え、温度はずっと1。実験してみた感じ下手に温度を変化させても良くならなかったのだ。これで13533820点。
あとは2時間近くずっと高速化をしていた。assertを外すと途端に3万回ほど多く回ってびっくりしたりしつつ、最終的には14万回ほど回っていたはず。ここでの最高値は13537765点だった。最後の0.2秒で最高スコアの解の山登りによる改善を試みたものが最終提出となり、13540250点を出して終了。
結果は13位で過去最高順位。予選を突破できたのも嬉しい。貪欲の13426585点は最終的に156位から199位までを占めており、これだけでオンサイトに進めたようだ。
TLで感想戦を見ながら振り返りをした。今回のコンテストは13426585点を出せるか出せないかで大きく明暗が分かれたようで、ヒューリスティックとしては異質かもしれない。最初の1時間を貪欲に捧げるという当初の方針がこのコンテストにピッタリだったのは運が良かった。強い貪欲を生み出せたのも運。アルゴの問題を解くのとはちょっと違った感覚だったから、単にレートが高ければ分かるというものでもなさそうだ。
焼きなましについて。温度1というのはつまり微妙な改悪を許しながらどんどん別の解を作っていくということで、最高スコアの解でも山登りで改善できる余地があるかもしれないというのは早めに気付くべきだった。というかそういう探索をするならビームサーチとやらを使うべきではなかっただろうか。
自分は貪欲の内部を一切改造せずに使ったが、「直上のボールは二つあるので書かれている数の大きいほうを選ぶ」に変化の余地があったらしい。ここは気付きたかった。13426585点が出た時点で満足してしまい、まともに考察できていなかったような感覚がある。
今回は動画を撮っていた。予選を突破できたら投稿しようくらいの気持ちだったが、思いがけずかなり良い順位のコンテストを記録できて嬉しい。
投稿作業を終え、いよいよ明日に迫ったインターン先勉強会の発表準備に取り掛かった。しかし眠気が強くまともに集中できない。ハーメルンなどに結構な時間を奪われていた。
日付が変わりTCB59が終了した。今回のセットは非常に難しかったためもしかしたら唯一の全完者かもしれないとワクワクしていたが、なんともう一人いらっしゃった。その方にはペナルティで大きく差をつけられており、2位。9問目の4ペナがひたすら痛い。9完に負けなかったのは良かった。
それからはもうほとんど発表準備が手につかなかった。眠気というよりは単にやる気が失せている。埒が明かないのでいったん寝て、起きてから頑張ることにした。午前5時就寝。