10/16(月)
午後2時くらいに起床。1時間ほどゴロゴロしてから起き上がり、購買に行ってお菓子・パン・本を買った。そのまま帰宅して食事はパンで済ませるつもりだったが、せっかくキャンパスに来たのだからと考え直して学食で食べて行った。
午後4時半からインターン先定例会。先週も相変わらずずっと学習を回していた。改善されている様子がなく、しかも回すだけ回して結果についての考察を全然やっていないため、話すことが本当にない。
勉強会はyukicoderで開催されたマラソンについてだった。3時間でテスターもビジュアライザもなしに取り組むには難しい問題に見える。実際解法もあまり理解できなかった。
しかしこういう状況を進行させながらパラメータを推定する問題は、推定フェーズと出力フェーズを分けられないという点に苦手意識があったので、一つ話を聞けて良かった。パラメータを最初適当に初期化しておいて、それを使ってクエリを投げ、返答を見て更新していけばよいらしい。言われてみればそれはそうか。更新は数式を弄るほか「粒子フィルタ」なるものを使う方法もあるようだ。
No.5018 Let's Make a Best-seller Book - yukicoder
かなり早めに解散となって、それから日付が変わるまでずっと週記を書いていた。TTPCとARCを残して投稿。
「赤点魔女に異世界最強の個別指導を!」を読んだ。鎌池和馬さんの新作。「未踏召喚://ブラッドサイン」が面白かったことを思い出して購入した。魔法の設定が非常に良かった。台詞に特徴的な語尾をつけて発話者を区別するのは、別に主人公でやる必要はないだろうと思ったが、そういえばブラッドサインでも「訳だが」という語尾が使われていたのだった。ただこの作品で使われたものはもうちょっと違和感が強い。
週記のARCの部分を埋めた後、読者になっているはてなブログの更新を久しぶりに読み漁った。シャワーを浴びて布団に入り、少しラノベを読んで午前7時就寝。
10/17(火)
午後3時起床。JOI一次予選の第2回過去問が公開されていた。昼前にはすでに提出があったようだが、遅ればせながらコードゴルフをした。
Aはdc。こういう問題はNibblesで書くと逆にとんでもないことになる。Bは相当をdcとNibblesで書いたら後者が1B短くなった……と思っていたところ、後から見たら==
でさらに1B縮んでいた。完全に頭から抜けていた。
CとDはどちらもNibbles。Cはにo
以外の文字数を足した。Dはiterate while uniqなるものを使って操作の無限列を得て、先頭から未満のものだけtakeした。
JOI 2023/2024 一次予選 (第2回) 過去問 - AtCoder
布団に戻ってR-18のハーメルンを2作読んだ。「とても都合のいいオナホ先輩」と「『最低』な彼は何でもお見通し」。後者はヒロアカの二次創作である。原作を読んでいないのでオリ主中心のハーレムに忌避感がないし、頭の中のイメージが原作の絵柄に引きずられることもない。ことR-18を読むにあたってはお得だった。
読んでいる間、午後8時から2時間くらい寝ていたようだ。次に布団から脱出したのは午前2時。ABC324のアマギフがもう届いていた。
食事してから先週のUC-Jを解説を見てupsolveした。「()頂点のグラフに対し、頂点集合であって誘導される部分グラフの辺の本数が偶数であるものを数えよ」という非常にシンプルな問題。解法もシンプルで汎用的に見えるのにあまり解かれなかったという点で、かなり良い問題だと感じた。
まず問題を多項式に言い換える。頂点に対し01の変数を定めると、辺についてという項がその辺が誘導されるか否かを表す。つまり2次の多項式についてとなる変数の割り当てを数え上げる問題になった。あとはグラフを忘れて解ける。
以降法を2とする。がを変数とする(高々)2次式であるとき、変数に着目するとと分解する。ここでなので、には変数は現れない。または2次式だったからは1次式である。の値で場合分けする。
のとき、とすることで、またそのときのみとなる。よってであるようなの割り当ての個数だけ解が存在する。は線形なので、この数え上げは容易。
のときであるから基本的にはを解けばよい。の制約は、例えばに変数が現れるならその変数をで表すことで保証できるから、それをに代入して新たな式を作ればよい。この操作で変数が1個あるいは2個減るため、繰り返せば解ける。
計算量は繰り返しが回、さらに内側で多項式の書き換えにかかるため。ただし変数がどんどん減っていくので定数倍はかなり良く、実際200ms弱で通った。
Submission #218334 - Universal Cup Judging System
2023/10/23追記:ABC220とほぼ同じ問題らしい。話題になったのも言われてみれば何となく覚えている。しかし当時はもっと違う言い方をされていた。
出てない回の UC に知ってる問題が出ていたらしい。https://t.co/K6hKLJ185s この問題と本質的に同じで、これを EntropyIncreaser が謎のアルゴリズムで解いているらしいということで一時期話題になっていた。
— 熨斗袋 (@noshi91) 2023年10月23日
朝までかけてラノベを2冊読了。
1冊目、「悪役御曹司の勘違い聖者生活」2巻。日記を読み返すと1巻の印象が悪かったらしいが、2巻はそうでもないどころかむしろ面白かったと思う。勘違いポイントはヒロインたる生徒会長の境遇に関するものだけだったので、どうすれ違っているのか分かりやすかった。また主人公が積極的に状況をコントロールしているようで満足。読んだ際の気分の問題だったのだろうか。
2冊目、「人数合わせで合コンに参加した俺は、なぜか余り物になってた元人気アイドルで国宝級の美少女をお持ち帰りしました。」。主人公の部活でありヒロインとの縁にもなっているサッカーの話が多かった。悪役ポジのキャラが不真面目なのにサッカーは上手いという奴で、一方主人公は目一杯練習していてもスタメン落ちというなかなか辛い設定になっていて目新しい。
午前8時半就寝。
10/18(水)
午後7時起床。
AtCoderの提出一覧の仕様が変わって1ページずつしか移動できないようになっていた。必要な提出だけロードすることによる高速化が目的だろうか。URLを弄ると遠くのページにも一度で飛べるが、読み込みに相応の時間がかかる。また全ての提出をロードする必要があるコード長や実行時間でのソートについては、当然ながら特に速くはなっていなかった。
提出一覧、AtCoder Jumper がなくなってこれになってた pic.twitter.com/LCIsOKOuMn
— ゴジラ@競プロ (@gojira_kyopro) 2023年10月18日
日付が変わったくらいに「間の悪いスフレ」を読了。「タルト・タタンの夢」「ヴァン・ショーをあなたに」「マカロンはマカロン」に続くシリーズ4作目の、日常の謎短編集……のはずが今回は社会問題やコロナ禍、ロシア・ウクライナ戦争の話が目につき、また謎らしい謎もないように見えてあまりミステリとしては読めなかった。
その後別の本を開いて朝方まで読んでいた。シャワーと食事を済ませてからセミナー準備として論文を読んだり先週に引き続いて少しサーベイしたりして、午前10時就寝。
10/19(木)
午後5時起床。生協に行ってラノベを買い、夕食を摂って帰ってきた。
それからずっと本を読んでいた。午前3時過ぎに「ロジカ・ドラマチカ」を読了。あらすじに「偶然耳にしたわずか1文・数十字をめぐる知の殴りあい」とあって、これは「九マイルは遠すぎる」のオマージュ作品だろうと買ったがその通りだった。短編四つで、特に最後のものは「ましてや~ならなおさらだ」という形のセリフが何度も何度も登場していた。
本家の流れを汲んでか、自分が覚えているオマージュ作品はどれも、なんでもない日常のセリフから犯罪の真相を暴いていたように思う。これは瓢箪から駒という感じで驚きではあるのだが、しかし論理の飛躍も大きいように見えてしまう。その点本作で考察の対象になった文はどれも明らかな不穏さがあったので、犯罪に結びつくことにはそれほど不自然さがなかった。
300ページの本に昨日と今日で14時間かけたらしい。それくらい文章を読むのに苦労した。まず作者の特徴として言い回しが仰々しく難しいというのがあり、加えて本作では精密な論理展開のために持って回ったような言い回しが多用されていた。自明とか同値とか敏感になるべき言い方もあって、その度に本当にそうか考え込んでしまった。
それから急いでセミナーの準備をした。何とか終わらせて午前9時半就寝。
10/20(金)
午後3時起床。予報によれば天気が崩れるタイミングがありそうなので徒歩・地下鉄で登校した。川内キャンパスの生協でラノベを買い、昼食を摂り、山へ。図書室に寄って教科書を借りたり雑誌のコピーを取ったりしていたらちょうどセミナー開始の時間になった。
午後5時から2時間は留学生の発表。論文の文章がなかなか意味不明だったが、具体例を見ようにも簡単なものしか手計算できなくて大変だった。ちゃんと理解するには参照元の論文まで読みに行く必要がある。
その後自分の発表の予定だったが、既に予定していた終了時刻になってしまったし、今週用意してきた内容で特に話したいこともなかったためスキップとなった。学食で夕食を摂り、閉店まで先生と1対1で話して午後8時半帰宅。
しばらくダラダラして、午後9時20分からyukicoder 409に出た。
yukicoder contest 409 - yukicoder
Aは頭が回っていなかったので真面目に計算した。最終的にが得られて題意を理解。Bはビームが通りしかないので頑張って列挙して全探索した。答えを求める部分にもかけてよいので、愚直。
Cはをメモした後を全探索した。最初で計算しておいて、をインクリメントするごとに条件に違反するをキャンセルしていけばよい。
Dはとりあえず立式してWolfram|Alphaに投げようとした。の最大値とその位置を固定すれば後は単純な二項係数になる。ところがここから最大値を動かしても位置を動かしても閉じた形になってくれない。仕方なく自分で解釈しなおすと、最大値を固定したときに左右それぞれのうちどれがあるか考えれば位置も定まることに気づいた。よって答えは。
EはまずDで出た式を閉じた形にしようとしたが、やっぱりWolfram|Alphaでもダメだったのでまた自分で。Dの解法は最大値の左右で分けたが、ここで最大値それ自身も左に入れてみる。すると求める値は左個右個から合わせて個選ぶ方法のうち、最大値が左にしかないものとなる。
最大値の出現パターンは左、右、左右の3種類あって、左と右は対称だから等しい。左右のケースは片方削除するとが一つ小さい問題の解となっている。よってに対する答えをと置いたとき、が成り立つようだ。
実はここから平方分割っぽく解ける。つまり、だいたい1000個おきにを計算した後上の式でまで列挙しつつ、が足りない分はその場で補ってクエリに答えればよい。
solved数を見てGに進んだ。が欲しい。ここで1の3乗根で1でないもの、つまりを満たすような数を考えると、であると分かる。よってが答え。
である。係数を取り外せば、に対しが求まればよい。ここで外のとキャンセルが起こり、を超える数の階乗が回避できる。
ここまで来て初めてにはが存在しないことに気づいてしまった。しかしなければ仮想的に作ればよい。結局と次数が大きくならないのが利点なので、FPSのべき乗とは違いは二分累乗法で高速に求まる。ここに気づくのにも時間がかかったが、何とか間に合った。
残り8分でF問題。かなり冴えていて、ちょっと考えたらすぐヴァンデルモンドの行列式だということに気づいたが、差の積を高速に計算するための手持ちがない。とりあえずTLE解を出しておいた。6完4位。
直後にFのupsolveをした。選んだインデックスの(順)列をとすると、となる。このに関する和はで定まる行列の行列式であり、はヴァンデルモンド行列を反転した形になるので、公式からが答えとなる。
この差積の計算を高速化する。といっても分割統治すればみたいな式が求まればよくて、をで多点評価すれば原理的には解ける。TLが6secなのでまあ通るだろう、ということでNyaanさんのライブラリをペタペタ貼った。
Multipoint Evaluation(高速化版) | Nyaan’s Library
符号についてはややこしいし、サンプルにはが偶数となるものしかない。一発で合わせることができてよかった。おそらく三つだがNyaanさんのライブラリが爆速でevilケースまでしっかり通っていた。
シャワーを浴びてから日記を書き始めたが、YouTubeを見てしまったりラノベに手を出したりと全然進まなかった。
午前9時就寝。
10/21(土)
午後7時半起床。食事して午後9時からABC325に出た。
KEYENCE Programming Contest 2023 Autumn(AtCoder Beginner Contest 325) - AtCoder
AはAWK。Bは世界標準時で何時に会議を開くか全探索する。CはBFS。
Dは見た瞬間にで区間スケジューリングをしたが落ちて頭が真っ白になってしまった。何か関連する話題があったはずと思って「区間スケジューリング」で調べたところ以下のツイートを発見。問題がほとんど一緒なので今回も想定嘘解法なのだろう。リプライツリーにあった解法をそのまま実装して何とかACした。
フェネック「区間スケジューリング問題を知ってるとRの昇順にソートして解こうとしてハマっちゃうかもねー。そういうアルゴリズムのhackケースは
— 競技プログラミングをするフレンズ (@kyopro_friends) 2021年8月14日
3
2 2
1 3
3 3
だよー」
Eは頂点とからそれぞれコストを変えてdijkstra。密グラフなのでの実装を用いた。
Fは「何番目の区間までを」「センサー1を何個」「センサー2を何個」使って覆えるかというbool値のdpを考えた。遷移はセンサー1を使う個数だけ全探索して。これだと計算量が大きすぎるが、値としてboolではなく必要なセンサー2の個数を持つと状態をに減らせて間に合う。
Gは区間dpで完全に削除できる区間を求めた。ある区間を削除できるか調べるためには、各文字を最後の操作で削除するか他の文字と一緒に以前の操作で削除していたことにするか決める必要がある。
最後の操作で何文字削除したか持って左から耳dpをすると状態数、遷移となる。まず遷移にはbitset高速化が効く。さらに区間dpの計算を降順・昇順で行うとを決めた瞬間に内側の耳dpを開始できる。以上でとなり十分高速。
1ペナ全完で9位。賞品の対象にはならなかった。Dのペナがなくても順位は一つしか変わらないようだ。その後Aだけコードゴルフをしたが、簡単なVimの8Bがあって開始1分半で提出されていた。
午後11時からTROC #35。
https://tlx.toki.id/contests/troc-35
Aは2023年に月日が存在するか判定。月日が存在するとかいう謎の制約のせいでどちらがどちらか分からなくなったため慎重に実装した。Bはインドネシア流の固有名詞がひたすら読みにくい。二人の人物と対応するパラメータに気を付けて読解したら後は算数。Cはの昇順に倒していくのが最適。
Dはかなり面倒そうに見えたがそこそこシンプルに解けた。水が張られている区間とその高さを持って更新していくことにすると、水が左右に溢れ出してから水位が元の区間と一致するまでの時間が知りたくなる。実はこのとき水が一方向にしか溢れていかないので、ある高さで壁がない区間は一気に水が張られる。よって単純なの和で書けてしまう。
Eはかなり難しかった。を決めたとき、の条件はと書ける。ここでとなる項の数を固定すると不等式の辺々の和がとなるが、を非負実数の範囲で自由に調節できるため、実はこれを満たす列には対応するが存在する。
を固定すると場合の数は2項係数で書けるから、その値を範囲内かつのもとで足し上げればよい。ここでを許すと2項係数の区間和となり、Wolfram|Alphaに投げると閉じた式になってくれるので、そこからの寄与を引くことで必要な値が求まる。
Fは整理が大変。まずcharmを使わなかった場合の移動方法は、経路を折り返すカタラン数の計算と同様のテクでで求められる。これで立ち入れない領域を避ける移動方法については求まるので、今度は立ち入れない領域に入る移動方法を考える。やが立ち入れない領域に含まれるケースは簡単なので先に処理。
それ以外の場合、初めて入る点と最後に出ていく点がある。この2点を固定するとその前後は同じ形の問題でcharmを使わなかった場合になっているので、先ほどの計算を流用できる。またcharmのパワーについてはとが条件。よって2点間を移動する方法以外の係数は独立に求めることができる。
あとはその、2点間の移動方法。まずcharmのパワーの条件から2点間に立ち入れない領域は存在しない。そして立ち入れない領域の形からが分かるので、これをと置くとが求める場合の数だと分かる。つまり座標の差にしか興味がないから、畳み込みでとなる2点について、先ほど述べた係数の積の和を求めておけばまとめて計算できる。
Gには手も足も出ず6完5位。それでもレートは2875→2906(+31)とかなり上がって、ランキング3位に浮上した。
TROC #35 oooooo- 5th
— こたつがめ (@kotatsugame_t) 2023年10月21日
2875 -> 2906 (+31)
インドネシアで3位 pic.twitter.com/5V83NeMAlU
午前2時からはMHC Round 2に出た。
Meta Hacker Cup - 2023 - Round 2
Aはよい。A1だけ実装するのは面倒だったのでA2も読んだら急に制約が大きくなってびっくりしたが、特に問題はない。Bはを左にrotateしていくので、大小関係の制約はあらかじめ個離れたところと比較した結果を持っておけば判定できる。回文の判定はManacher。
Cが一番難しかった。トピックを一つ固定すると木dpで解けるが、部分木の状態を「完全に分解できた→0」「そのトピックを持たない根からのパスが1本残っている→1」「アウト→2以上」と定めると、だいたい和によって遷移していける。状態をオフセットとそこからの差分として持つと、部分木に存在しないトピックは差分0で表現できる。よって出現したトピックの差分のみマージテクで管理すればまとめて計算できる。
Dは二人が選んだのGCDがの約数であることが必要で、十分でもある。一人1種類ならこの十分性は有名事実。2種類以上のを持っているときは十分高いタワーをGCD刻みで作れることから従う。そして個の選び方をGCDごとに数え上げるのは約数除原理の典型。が小さいことは使わなくてよい。
全部通って9位。かなり簡単なセットだった。今回はR1のようなシステムトラブルがなくて良かった。
日記を書いて午前10時就寝。
10/22(日)
午後3時半起床。午後4時からCF #904 div.2に出た。
Dashboard - Codeforces Round 904 (Div. 2) - Codeforces
Aはの間には必ず存在するため見つかるまで探索してよい。この簡単な事実が思いつかないまま雰囲気で通して、証明はコンテスト後につけた。Bは右にある0
から順に自分より右にある1
の個数を数え、足し上げればよい。
Cはを取るインデックスを固定したときそこを覆う区間はすべて使わないとしてよい。するとそこから左右に分けることができて、それぞれ区間ADD・区間MAXの遅延セグ木でシミュレートできる。Dは昨日のMCH R2-Dと同様に解ける。
Eは大変だった。最適な操作は、最小値が連続する極大区間を埋めていくことで達成できる。これを逆から考えると操作する区間がその中の最大値でどんどん分割されていくように見える。最初にを満たすようrotateしてから解くと、このときの操作がデフォルトの状態だと思えて、数列をrotateするごとに端に来た区間だけ二つに分裂しその分操作回数やコストが変化する。
例えば区間があったとしよう。先頭要素が(ただし)のとき、この区間はとの二つに分裂する。つまりコストの変化はであり、インデックスに関する2次関数で書けるので区間加算が可能。
あとは区間を(重複をまとめて)列挙しセグ木で処理。遅延セグ木ではなく双対セグ木を使ったり、更新が可換なので遅延したものを下に流さないようにしたり、最後の1点取得回の前に遅延した更新を一気に反映したりと高速化を入れて2700msだった。
全完4位。
AHC025が終了した。結局初日の最初の1時間しか参加しなかった。アイテムを適当に振り分けた後、重い集合から軽い集合へ一つ移して重さの大小関係が変化しないケースのみ採用という山登り。1点swapで改善したかどうかすら分からないと思い込んでいたが、さすがにこれはまともに考察していなかっただけだと信じたい。
AtCoder Heuristic Contest 025 - AtCoder
AtCoderの提出ボタンが変なところに判定を持っているらしい。自分でも試してみたら本当に押せてしまった。これまで暴発した経験がなかったのが奇跡に思えてならない。
AtCoderの提出ボタン、紫の四角の範囲にも当たり判定あって(空のlabel要素がある)、思いがけないタイミングで提出されてしまった… pic.twitter.com/9ojStLWJLK
— tomerun (@tomerun) 2023年10月22日
食事して午後8時からCF #905 div.1。div.1からdiv.3まで三つ同時開催という見たことのない形式だった。
Dashboard - Codeforces Round 905 (Div. 1) - Codeforces
A1から大変。、はソート済みであるとする。最終的な項数をと置くと、に対しが条件。ここでなる最小のをと置くと、となる。をインクリメントしつつ判定すればよい。念のため、答えはではなくである。
A2はこの方針だと難しい。まずを長さの列のままにしてA1と同様にを求める。そこにを追加してもは高々1しか増えないので、1増やせる最大のを求めた。を追加するとそれより小さいについてペアを組むがずれ、小さくなる。これが許されない最小のを探すとが入る位置が決まり、ペアとなれる最大のもわかって最大値が求まる。
完全に出遅れ、焦りながらBへ。こちらは簡単。すべての辺を集めてグラフを作り、たどり着くタイミングを距離としてdijkstraを行う。辺を通る際はそれが使える直近のタイミングを調べる必要があるが、まあ何でもできる。尺取りみたいな感じでは落としておいた。
Cは実装に苦労した。数列の先頭の項から最小値を求めていくことにする。各項についてどのクエリで最小値を取るかだけなら、クエリ番号を遅延セグ木のインデックスにしてクエリを載せたり降ろしたりしながら数列を舐めればよい。しかし本当に欲しいのはこれまで最小値を取り続けたクエリのみ考えた時の最小値である。
そこで、最小値を0に揃えてを掛ける更新を間に挟むことにした。こうすれば最小値を取り続けない限り一瞬でに飛んでしまって、以降最小値の計算から弾かれる。実際にはではなく十分大きな値を使い、オーバーフローしないよう注意して区間ADDと区間倍の更新を表現した。
更新のためlong long二つとboolを持った最初の提出は3secギリギリだったので、リサブ。boolを持つのをやめ、片方のlong longを特殊な値にすることで表現したら1sec以上高速化した。
それから残り50分あったのにDを通せなかった。Cまでの4完142位でレートは3095→2969(-126)。LGMを保つことができない!Aはやを二分探索すればよかったらしい。真面目に頭を使っていたのがバカらしくなってしまった。
Dは4ケース目でずっと落ちていたのだが、コンテストが終わって一息つきランダムケースを試したらすぐ間違いが見つかった。ただ修正レベルではなく解法の根本的な見直しが要求され、相応に時間もかかったのでどうしようもない。
が固定されているとして、各について「区間とに分けることが可能な最大の」を管理した。これををデクリメントするごとに差分更新していく方針。コンテスト中はから右に見た時の累積MAXや累積MINを見て適切に区間chminをしていけばできると考えていたが、できなかった。
を中心に変化を考えるのが正解。から右に見た時の累積MINの更新点を列挙すると、はそのどれかにしかならない。をデクリメントしていく際どのタイミングでが変化するかが求まるので、これを記録して適切に1点更新すればよい。記録すると同時に累積MINの更新点が消えるので、更新は回になる。
午前0時からUniversal Cup 6回目、Warsawセットに参加した。今週はMHCがあってこの時間帯にもwindowが追加されていた。
The 2nd Universal Cup. Stage 6: Warsaw - Dashboard - Contest - Universal Cup Judging System
書く:UC
日記を書いて午前10時就寝。