週記(2021/09/27-2021/10/03)

09/27(月)

先週は週記を書いてからすぐ布団に入ったが、そのあとPixiv小説をちょっと漁ってしまい、結局寝たのが午前8時半だった。

午後1時半起床。しばらく布団でウダウダした後、大学生協に行って注文していた本を受け取ってきた。

午後3時からインターンの業務を進める。先週したことをまとめて、直後に迫った定例会で報告するための資料を作っていた。載せるデータを吟味していたら思ったより時間がかかり、ギリギリになって完成。発表自体は特に問題なく済んだが、そもそもデータが足りていないのでは?という話になって、アクセス権限が足りていない可能性があることが分かった。これは困った。とりあえず明日の1on1で話し合ってどうにかする予定だが、それまではすることがない。まあ今日は週末の疲れが残っているので、することがないならないで今のうちに体を休めておく。

Kaggleの新しいコンペが始まって、これはチーム制限が5人なので、ちょうどインターン先の興味があるメンバー全員が1チームにまとまることができる。早速チームを組むことになった。以前の週記で言及したかもしれないが、一応今Optiver云々というコンペに個人で参加してはいるものの、興味が離れて最近は手付かずだった。出だしで躓いていては世話がないので、何とかこの新しいコンペで自分なりのKaggleへの取り組み方というものを見つけたい。しばらくはコンペの内容だったり公開カーネルを読んでいた。

余った時間で、Kaggleに興味がある面々が集まってチームを組もうという話になった。チームを組むということ自体に非常に興味があって、ぜひやってみたかったのだが、残念ながらコンペのチーム人数制限が3人だったので組めなかった。以前は5人だったらしい。

週記(2021/09/06-2021/09/12) - kotatsugameの日記

CodeChefの先週のコンテストまとめ記事がメールで送られてきた。div.3の優勝者の部分に自分の名前が載っていて気持ちいい。自己顕示欲が満たされていくのを感じる。

ラノベを1冊読んだ。「王様のプロポーズ」。「デート・ア・ライブ」の著者・橘公司さんとイラストレーター・つなこさんのコンビの新作で、あらすじもかなり面白そうだったので、楽しみにしていた。実際素晴らしく面白かった。まず設定が自分の最近の好みにピッタリ一致していた。「最強の能力者」も好みだし、「主人公が学園長」も好み。しかも「学園長がその学園に通う」という展開に至っては、好みに好みが掛け合わさって掛け値なく最強に見える。そういうストーリーがありなのか。まさにコペルニクス的転回と言って過言ではないだろう。

序盤はいろいろ後に続きそうな展開が盛りだくさんだったので、もう何巻か出ることを見越して、1巻は準備の巻かなと思いつつ読んでいたが、思いのほかラストで話がまとまってびっくりした。非常に満足したが、2巻以降への期待が薄れたわけではない。あとがきによれば続刊が出ることが確定しているわけではなさそうだったが、ランキングを見るに売れ行きは好調なので、きっと出てくれるだろう。

実はかなり眠くて、ラノベを読んでいる間ちょっと意識を飛ばしたりしていたが、ラストが良かったので目が覚めてきた。次に「デート・ア・ライブ マテリアル」2巻を手に取って読み始めた。著者とイラストレーターの対談を読みながらその巻を思い返して非常に感慨深くなっていた。12巻などは男主人公がピンの表紙イラストになっていて非常に好みだった。この巻が出た頃に既刊を一気に買ったことを覚えている。

そこそこで切り上げて、ABC220-Eのコードゴルフをした。この問題はPythonによるゴルフがしばらく行われていたようで、なかなか短い計算式が以下のように最短を保持していた。しばらく考えていたら自分でも再現できたので、安心。

atcoder.jp

基本的に解説と同じ方針、つまり2頂点のLCAを固定して数え上げている。LCAの深さが0\le i\lt Nであるとすると、まずi+D\lt Nであれば答えに2^D\times 2^iが足され、さらにD\gt 1であれば、0\lt k\lt Dかつi+k\lt Nかつi+D-k\lt Nなるkの個数に応じて2^{k-1}\times 2^{D-k-1}=2^{D-2}かける2^iが足される。最後に、以上で求まった組の左右を逆にしたものを考えて、答えを2倍すればよい。2倍するのも2のべき乗を求めているときに行うことにすれば、i+D\lt Nのとき2^{D+i+1}を、また上の範囲の幅に応じて2^{D+i-1}を掛ければよいことになる。D\gt 1という条件は、この式変形によって必要なくなる。2^{D-2}を計算しなくなるし、D=1のときはkが取りうる値の範囲が常に0に等しいからだ。

さて、kの範囲をより精密に考える。区間の右端としてN-iまたはDを、左端としてi+D-Nまたは0を考えるので、この2×2を計算してminを取ればよい。計算すると、区間の幅は\min(2(N-i)-D,N-i,D)-1になるようだ。k=N-iとおいて場合分けすると、k\gt Dのときは\min(2k-D,k,D)=Dであり、k\le Dのときは2k-Dとなる。ここで区間の幅は正になる必要があるため、2k-D\gt 0よりk\ge\left\lfloor\frac D 2\right\rfloor+1が必要となる。

i+D\lt Nという条件はD\lt N-i=kと書き直せるから、結局1\le k\le Nに対してk\gt Dならば2^{D+N-k+1}+2^{D+N-k-1}\times(D-1)k\le Dならば2^{D+N-k-1}\times(2k-D-1)を答えに足す、とまとめられる。前者を2^{D+N-k-1}でくくり、kの代わりにk-1を考えれば、先の提出の式が得られる。

試しにdcで計算してみたところTLEしなかったので、それで縮めることにした。毎回2のべき乗を計算するのはまずいが、kのループを降順に行うことで、ループごとに2倍するだけで計算できるようになる。掛け合わせる数の場合分けは単純なminというわけにはいかないが、何とかして、73Bの解ができた。制約にD\le 2N-2がなくてキレそう。

atcoder.jp

布団に入って少しだけハーメルンを読み、午前8時前就寝。

09/28(火)

昼前、腹を壊して目覚める。トイレに行った後またすぐ寝て、次に午後3時半に目覚ましで起きた。午後4時の1on1のためにかけていた目覚ましだったが、ギリギリに起きるのも怖いものだと分かった。

明後日木曜日のCHUNITHMのアプデ情報が来ていた。もう見るからにラスボスですごい。@anayama_daisuke というラスボスの曲ばかり作っている人のアカウントが昨日の夕方にそれっぽいツイートをしていたので来ること自体はわかっていたが、作曲者が5人もいるのにはびっくりした。「ep. Grandioso」というマップ名も特徴的。

今日の1on1は、昨日から特に進捗もなく、やっぱりデータ足りていないですねという話になって、権限付与が完了するまではインターンに関係ないことを済ませておくことになった。具体的には10月第一週の木曜日に迫った4年ゼミの発表準備である。

1on1が終わって、あまりに眠いので布団に戻った。しばらくスマホを弄っていたが、午後6時半くらいに本格的なお昼寝の体勢になり、そのまま日付が変わるまで寝ていた。ここで日記の日付も変えておくのがよいと考える。

09/29(水)

午前0時起床。僕が寝ている間に権限付与が完了していた。素早い対応に感謝。

@anayama_daisuke というアカウントから、ラスボス曲の譜面の一部が動画でツイートされた。数年前に混沌で初めて見たときはびっくりしたが、これも恒例行事。25秒の動画からいろいろ情報が得られる。まず譜面定数14.0以上が確定し、この時点でレート理論値が16.00を超えることが分かったらしい。一体何色の表示になるのだろうか。またノーツ数は4444で、これはつい最近出た「赤壁、大炎上!!」を抜いて最多ノーツ数である。タップスライド以外での16分割タップも当然のように配置されており、新時代という感じが強い。

CF #744 div.3が始まっていたので、1時間遅れで参加し、1時間弱で全完した。

Dashboard - Codeforces Round #744 (Div. 3) - Codeforces

Aはよい。Bは先頭から合わせる。Cは作れるチェックを全部作る。Dはよく難しい問題の部分問題として見る設定で、多いもの2つをどん欲に組にしていけばよい。特に証明したわけではないが……いいだろう。個数の最大値が小さければそれだけ自由度がある。E1は後ろから見て残りの最小の要素を先頭に、それ以外を末尾に入れる。E2も後ろから見ると、その要素が絡む転倒数が計算できるため、小さいほうに振り分ければ残りの列はそれだけで考えればよいことになって、貪欲。Fは操作でANDを取ることになる列たちに分解し、それぞれ全部0になるまでに必要な操作回数を計算する。Gはdpで、現在の終点からすでにカバーした範囲の左右までの距離で状態をまとめられる。これでも状態が3次元だが、bool値のdpになり、実際1つの次元の値は最小値さえ考えればよいことが示せるので、2次元のdpに落とせる。

ARC084-D「Small Multiple」が縮められていたので考えていたら、大幅に縮め返すことに成功した。

atcoder.jp

01BFSをするため、配列の先頭と末尾に挿入する必要があって、コード長的にも実行時間的にも重かった。これを、コスト0で遷移するループとコスト1で遷移するループをうまく分けることで解消でき、しかも短くなったというのが驚き。リストを用意して先頭から走査する。コスト0の遷移についてはリストの末尾に追記することで、同じループでそのまま走査していってくれる。コスト1の遷移は、今見ているリストを書き換えることで次回のループの時に走査してもらう。コスト自体は外側のループで管理しているため遷移の際に考える必要はなく、ゴールにたどり着いたと判定されたら外側のループを抜ければOK。

デート・ア・ライブ マテリアル」2巻を読んだ。設定の話とかは非常に興味深く読めたが、正直ゲーム特典SSなどはゲームオリジナルキャラをよく知らないため、微妙……。あとは作中時間も大幅に前後しているため、あまり出てこないキャラがいたりするが、短編集として出されているわけではないため我慢できる。ゲーム展開もしているなんてすごいことではないか。

インターンの業務に関連して、新しく使えるようになったデータを処理するコードをずっと回していたが、全然終了する気配がない。このあたりのコードの改修をデータが非常に少ない状態で行えたのは、むしろ僥倖だったのではないかという気持ちになってきた。

午前10時になったのを見て、学食に行くことを思い立つ。営業時間を確認すると午前8時から空いているようだったので勢い込んで行ってみると、午前11時半からの開店だった。実は僕が見ていた営業時間の表は、10月からのものだったのだ。仕方なく、購買で少し買い物をした後は前の広場で1時間くらいハーメルンを読んでいた。

食事して帰宅。ツイッターを見ていると、「ゴルゴ13」で知られるさいとう・たかを氏が亡くなったとのニュースが流れてきた。生前から漫画の分業体制を整えていたという話で、この先もその体制を維持してゴルゴ13の連載は続けられるらしい。

ラノベを読んでいたが、午後3時くらいに急激に眠くなり、布団に倒れこんだ。午後11時まで寝てしまった。とんでもない生活リズムになった。

起き抜けに確認したこととして、まずCF #744 div.3のHackフェーズが終了し、全完が確定していた。次に、寝落ちするときにも動かしていたスクリプトがエラー落ちしていた。実際はPythonスクリプトいくつかをシェルスクリプトでまとめていただけなので、それ以前のスクリプト(8時間かかっていた!)の出力は保存されているが、エラーの原因がスクリプト名指定ミスでげんなりしてしまった。

今日の初めのほうで縮めたARC084-Dがさらに縮んでいた。Vim部分の更新で、ある行の左と右にそれぞれコードを挿入したい場合、IAを使うとセミコロンが必要になるが、Ioだと改行がコードの区切りになってくれるという話らしい。同様の手法が適用できるコードがいくつかあったので、探して縮めていた。

atcoder.jp

ゲノコン2021のシステムテスト・表彰式が終了して提出がすべて公開されたので、AtCoderProblemsでクロールされるようにプルリクを出しておいた。ゲノコン2021のD問題は、適当な文字列を2回出力するTextと、入力の1行目を2回出力するsedコードを提出していた。Textについては空文字列を2回出力する2BでACできたが、sedはさらに短く、pのみのコード1BでACできた。どうやら、出力の先頭2行を読み込んだら残り何が出力されていてもどうでもいいらしい。

Add genocon2021 by kotatsugame · Pull Request #1066 · kenkoooo/AtCoderProblems · GitHub

起きて落ちていることを確認したスクリプトだが、改めて実行してしばらく放置していたところ、どこからかキィーみたいな音が断続的に発生するようになった。恐る恐る部屋を調べていると、パソコンから出ていることが分かった。HDDのシーク音だろうか。確かにファイル読み書きが多く発生するスクリプトなので、しばらくは我慢だろう。で、我慢していると実行が終了した。これまで扱ってきたファイルよりサイズが非常に大きいらしく、書いたコードが一部動かない。とりあえず、ファイルサイズをヒストグラムにして確認したいと思ったので、サイズをcsvファイルに出力するのはPythonで、ヒストグラムOctaveなんぞ起動してちょっと弄っていた。いい感じのグラフができて満足。

あとは、今まで長い時間をかけて作ったデータを機械学習のコードに流し込んで動かす。スクリプトを実行してみると、今度こそパソコンのファンの音がすごいことになったが、触ってみた感じ熱を持っているわけではないので、安心。ただデータが増えたのでかなり時間がかかりそう。寝ている間に終わるだろうか。

布団に移動して俺ガイルの新刊を読んでいた。途中、「知識の泉」と「混沌の欠片」という単語が出てきて、GOSICKのネタだと気づいた。あまりにも脈絡がなくてびっくり。そういう風に出てきたネタであって、気づかず通り過ぎたものがいくらでもあるんだろうなあと残念な気持ちになった。

午前5時半就寝。

09/30(木)

午前9時半起床。すでにチュウニズムのアップデートの情報がいろいろ流れてきていた。レート16.00を達成した人も現れた。レートの色は変わらないようだが、称号が虹色に光っている。非常にカッコいい。この「皇帝」という称号は、チュウニズムの現行バージョンでレート16.00を達成することが条件のようだ。わざわざ現行バージョンという制限を付けたということは、次回作からレートシステムに変更が!?……というようなことを考えていた。無論僕の実力的にはほとんど関係のない話であって、ただのランカー厨。

せっかく起きたので、SRM814に出た。全完4位、2443→2540(+97)。SRMで全完するのは初めてかもしれない探したら2年半前に全完していた。

https://community.topcoder.com/stat?c=round_overview&er=5&rd=18888

Easyは前にしか進まなくてよいことを確認してやるだけだが、制約が5\times 10^5なのでスライド最小値でlogを落としておいた。Mは素因数分解して各素数の指数を見る。素因数分解100\times\sqrt{10^{12}}で、毎回やって間に合うか不安だったので、素数を前計算しておくことにした。置き換える値はALCAでよく、LCAが一致しない場合は必ず1個置き換える必要があることに注意。Medを落とした人はこれを見落としていたらしい?

Hardは2べきで作ろうとしたが難しそう。適当に1直線にマスを置いてみたところ、トリボナッチ数列が現れることに気づいた。フィボナッチ数列を適当に組み合わせると任意の正整数が作れることは有名だが、ではトリボナッチ数列では?と思って探索してみると、制約の範囲内(109以下)ではちゃんと作れることが分かったので、この方針で実装。1直線のマスの適切な位置から分岐して、残りが1本道になるようにしたい。別に3本くらい1本道を用意しておいて、そこに合流させることにした。分岐が連続すると、その間で移動ができてしまうな……と思っていたが、逆に連続した分岐はそこで1本道にまとめてよいことに思い至り、あとは右下を手作業で構築して完成。

昼頃1on1をした。昨日パソコンをぶん回した結果を報告した。データに不要な箇所が大量にあるという指摘を受けて、それを単純に削除して様子を見て、また明日の1on1で報告することになった。業務ばっかりやっているようだが学業は大丈夫か、と心配していただいた。そのあと閉店前の学食に急いで駆け込み、食事。

帰宅してラノベを読んだ。「やはり俺の青春ラブコメはまちがっている。結」1巻。年末年始の話を、由比ヶ浜結衣に着目して描きなおした感じだろうか。正直この辺り、本編で描かれたのが昔過ぎてあまり覚えていないが、覚えていなくてもエモいものはエモい。

チュウニズム14新曲の譜面動画がYouTubeに投稿されていたので視聴していた。MASTERで16分割ノーツが多用されているのは当然として、赤譜面にも16分割があってびっくりした。動画のコメントを見た感じでは振り下ろしエアーも赤譜面初らしい。

明日から新学期なので、履修計画を立てようとしたが、春先にダウンロードした資料を夏休みの間に削除してしまったらしく、新たにダウンロードしてくる羽目になった。院試に合格したので大学院の講義を先行履修することができるらしく、どんな講義があるのか調べてみたところ、4年生向けの講義と全く同じでびっくりした。つまり、同じ講義でありながら4年生向けとして履修すると学部の単位になり、大学院生向けとして先行履修すると大学院の単位になるらしい。学部の単位はもう足りているので、先行履修できないか4年ゼミの教員に聞いてみたいと思う。

午後7時過ぎからCF #745 div.1。10分こどふぉった。4完15位で2952→2998(+46)。あと2……。

Dashboard - Codeforces Round #745 (Div. 1) - Codeforces

Aから難しい。単純に4乗したくなるが不可能で、2乗で幅を決めた後、累積minなど使って高さを決定することにした。累積minの計算にも、ある行の区間内の'1'の個数を定数時間で求める必要があったりと、非常に面倒だった。

Bは非常に難しい。挿入dpでもどのように挿入するかが問題。大きい要素からどこに配置するかを決定するのが正解。今のところ最大値として何種類ありえるかをインデックスごとにカウントしておきたい。これまで配置した要素で数列はいくつかの区間に分割されるが、この区間内でカウントの値はすべて等しいから、区間の幅O(N)とカウントO(N)で状態をまとめることができる。それぞれ、区間内のgoodな要素の個数O(N)に対応して場合の数を持つ。遷移は、区間内のどの位置に要素を置くか、左右でgoodな要素がいくつあるか、でO(N^3)になる。O(N^5)で一度TLEを食らった。goodな要素はそれほど多くならないので、余計な個所を見ないようにすると通った。

Cはx_i+y_iの値が\sqrt nより大きいかどうかで処理を分ける。大きい場合はimosで愚直にカウント、以下の場合は\bmod{x_i+y_i}のテーブルを用意しておいて、そこを書き換える。imos法を使うことでlogがつかないようにした。おそらくそれを要求するためのTL 1secだろう。Dは、区間の最大値で分割して、マージに左右の列の長さの積だけかかるdpを書いたら爆速で通った。やっていることは、数列から作られるCartesian Tree上の2乗の木dpと同じらしく、このことから計算量解析ができるらしい。適当に投げてしまったが、面白い。

システスで上から4人ほど落ちて15位になり、LGMまであと2になってしまった。BとCで1ペナずつ吐いていて、どちらかがなければ14位だったのでLGMを達成していただろう。特にCのWAは、スコープ外の変数を書き換えるつもりで新しく変数を用意していたという理由だったので、非常に悔しい。処理を変えるしきい値を小さくしてデバッグするのをすっかり忘れていた。

「株では勝てる俺も、カワイイ女子高生には勝てない。」2巻を読んだ。1巻の個人的な評価は低めだったが、2巻は思いのほか面白く読めた。主人公に人間性がない描写は控えめになっていて、多少受け入れやすかった。ヒロインがディープラーニングで株価変動を予測しようとして、案の定莫大な損失を抱えてしまうという展開は、導入部分から破滅が約束されていて目も当てられなかった。それでもラストはいい感じに落ち着いたかと思ったが、急に不穏な感じの描写が挟まって心臓が休まる暇がなかった。

動画を見たりしているうちに、うっかり椅子の上で意識を飛ばしてしまった。ふと目を覚ますと、昼の1on1が終わってからずっと動かしていたスクリプトが最後の最後に「強制終了」と出て落ちていた。そういうエラーメッセージが出るような落ち方とはいったい何だったのだろうか。必要なデータは適宜ファイルに書き出してあったので、とりあえずそれを処理するコードを動かして布団に移動し、改めて寝た。午後11時半だった。

10/01(金)

午前6時半くらいに目を覚ました。その時はいい感じに眠気が残っていて、またしばらく眠れるはずだったが、うっかりスマホを手に取ってしまい全てが崩壊した。

Twitterで何かのゲームと東方がコラボしたときの霊夢が流れてきた。なかなか可愛らしい。

布団から出て、今日の夜にCFで行われるICPC WF MirrorにICPCチームで出るため、人をinviteしたりレジったりしていた。Slackに投げるとすぐ反応があったから、実は見てくれているんだなあと感動。僕が引きこもっているだけで、誘えば普通にICPC練習を連打できるのかもしれない。もしくはたまたま僕から誘ったから無理して出てくれたのか。

数時間かけて日記を書いて、読書記録もつけて、9月分の集計をツイートした。今月は結構読んだし、あまり本を買わなかったので、久しぶりに積読の数が減ったらしい。焼け石に水な気もする。

そのあとは今学期の履修登録をしていた。昨日も言及したが、改めて大学院の科目で先行履修したいものを選び、4年ゼミの指導教員にメールを出す。すると一瞬で承認してもらえたので、そのメールを証拠として含めて、改めて大学の事務方にメールを送信した。また、通常の履修登録の画面を開いて、1講時ずつ履修可能な科目を確認していく。科目名で気になったものがあれば、シラバスで内容を確認してみる、という感じ。

意識が高すぎてさらに2科目履修登録してしまった。「Pythonによるデータ科学入門」と「計算物理学」。どちらもPythonでプログラミングをする何かである。前者は、最初数回以降は対面で講義を行うというようなことが書かれており、不穏。しかし学部生活最後であることだし、講義棟まで足を運ぶのも一興か(こんなこと言っていて、どうせその日になれば行かない確率が高いが)。プログラミング関係では、探せばR言語を学ぶ講義もあったのだが、グループを作って発表しあうというようなことが書かれていてスルー。他に「インターネットを誰が守るのか」とか「批判的思考と論理的文章」という講義にも興味を惹かれたが、冷静に自己診断すれば面倒さが勝ることに気づけた。

これで今学期は講義を3つとる予定だ。それらのクラスコードを探してClassroomに登録し、ちょっと中を覗いてみた。まだ初回授業前なので、特に見るべきものはなし。

富士見ファンタジア文庫が、自社ラノベのキャラを集めて作ったクロスオーバーRPG「ファンタジア・リビルド」がある。ラノベの帯によく広告が出ていたので認識はしていたが、残念ながら今年の12月、公開から1年でサービスを終了することになったらしい。シナリオ担当もキャラも、ラノベ読みからしたら超豪華な布陣だが、ゲーム業界は厳しいものだ(プレイしていないのにどの口が言うか)。

午後になってしまったので、学食が閉まる前に急いで大学生協に行く。行きは普通に雨が降っているなあという感じだったが、ちょっと昼食を食べているうちに土砂降りになって、靴の中を濡らして帰ってきた。濡れた靴を乾かすため、わざわざ実家から送ってもらった古新聞を詰めていたら、その新聞がコロナ禍前のものであることに気づいて、ちょっと感慨深くなった。

自分は出不精なものだから、コロナ禍でも比較的影響を受けなかった人なのかもしれないが、影響がゼロというわけでは決してない。外出時にマスクが手放せなくなったとかそれ以前に、人が密集している状態に違和感を覚えるようになってしまったのだ。これはTwitterでもたまに流れてきた話で、過去の写真や動画などを見ていても、密な状態を検出して勝手に嫌な気分になってしまう。我々の認識の根幹を揺さぶってくる、そういうウイルスだったのだ。

そのとき考えていたことを時系列で並べているだけなので、話は変わるが、「ら抜き言葉」について。可能の助動詞「れる・られる」の使い分けは、付く動詞が五段活用・サ行変格活用の場合前者、それ以外は後者である。このことは高校生のころよこに教えてもらったもので、それ以来この判別に従ってらを入れたり抜いたりしている。僕が文章を書くときは、その判別でちゃんと思考が一時停止するため、週記でもら抜き言葉が出現しないようになっているはず。

眠気が強くなってきたので、午後5時の1on1まで1時間ちょっと寝ることにした。布団に入って人の週記を読んでいたら思ったより時間が経ってしまい、90分周期の睡眠が難しい状態になったが、強気のお昼寝。ちゃんと1時間時点の目覚ましで目を覚まし、しばらく布団の上で唸っていたものの、無事身を起こすことに成功した。

実は昨日の夜CFに出つつパソコンをぶん回していたので、1on1で報告すべき進捗はちゃんと用意されていた。いよいよ機械学習が本格化しそう。毎日作業を進めるのではなく、いったん時間を取って使いそうなモデルについて学び、実際にデータに適用して理解を深めることになった。

午後7時半から午後9時までまたお昼寝。今度も起床に成功して、yukicoder 316に出た。1時間で3完して午後10時からCFに出た。

yukicoder contest 316 - yukicoder

Aはよい。Bはコインの枚数を決め打って必要な操作回数の最小を考える。必要な操作回数の最小がk回だとすると、左端からkマスにはコインが置いてある必要があって、それ以降は自由なので、組み合わせで計算できる。Cはちょっと手で試した感じ0110の交換だけ考えてもよさそうな気がしたので、1がどれだけ動いたかを持ってdpしたら通った。後から解説を読んで証明を確認。操作によって、文字列の先頭から各1までの距離の和が変化しないことを使って示せるらしい。

残りは難しそうだと思ったので放置してCFに専念していたのだが、思ったより解かれていて順位がひどいことになった。ともかく、CFのICPC WF Mirror。5時間のコンテストである。

Dashboard - ICPC WF Moscow Invitational Contest - Online Mirror (Unrated, ICPC Rules, Teams Preferred) - Codeforces

ひどい目にあった。序盤EとHが解かれていて、Eはすでにチームメイトが取り組んでいたのでHを読んだ。Hは構文解析やるだけで15分で通ったが、以降L問題にハマり続けて4時間45分椅子を温めた。コンテストが終わってTLに流れてきたツイートを読んでもピンと来ていない。

しばらく日記を書いてから、朝方、ふとあるGitHubリポジトリのcollaborator一覧を確認したくなった。普通にGUIから見れるものだと思っていたが、認証付きAPIを叩かなければいけないらしい。調べたQiita記事ではPostmanを使って、通常の認証としてユーザ名・パスワードを入力しつつ叩いていたが、僕が試した限りではブラウザのURL欄に直打ちするのと同じく認証が必要であるとの文章しか返ってこなかった。やはりOAuthを使わなければどうしようもなさそう。公式ドキュメントを確認したいが、かなり眠気があって英語を読むのが辛いな……と感じていたら、日本語のドキュメントを見つけた。これに従ってやってみると上手くいったものの、自分が管理しているリポジトリでないとcollaborator一覧が取得できないらしく、結局ダメだった。

REST APIを使ってみる - GitHub Docs

布団に入って少しラノベを読んだ後就寝。午前7時半だった。

10/02(土)

途中何度か意識を取り戻した記憶はあるが、そのたびにまたすぐ寝直せていた。結局午後8時起床。

寝ている間にチュウニズム14新曲のAJが陥落していた。初日AJが出なかったのはバンキシャ以来だということで話題になっていた。バンキシャが追加されたのは僕がチュウニズムを初めてからで、それほど昔とは思っていなかったが、調べてみるとほとんど4年前の楽曲らしかった。

atgolferにいくつか更新が流れてきており、それらを確認しているうちに午後9時になったのでABC221に出た。G以外の7完。

AtCoder Beginner Contest 221 - AtCoder

Aはdc。プルプルしながらタイプしていたらFA+1秒だった。Bから面倒だったのでC++。Cは分割パターンさえ全探索すれば、それぞれは降順ソートするのが最適。Dは何も考えずに座圧してimosしたが、普通にソートした後カウント変数を管理するだけでも良かった。Eは「取り出した列の第2項以降が初項以上である」という条件だと勘違いしてしまった。この勘違いはサンプル4でしか落ちないので、念のため確かめてギリギリセーフ。誤読を修正するのにもいくらか時間がかかった。気づいてしまえばあとはBITで管理するものを変えるだけなので、簡単。Fは、まず適当に直径パスを取ってくる。直径パスの中心がちょうど頂点なら、そこから出ている辺の先にある頂点(十分な距離があるものだけを考える)をそれぞれ選ぶか選ばないかという話になる。2つ以上選ぶ必要があるので、ちょっとしたdpを行った。中心が辺なら、辺の両端の先にある頂点をそれぞれ選ぶ必要がある。

Gはしばらく考えていてもよくわからなかったし、そうしているうちにHのsolvedが増えてきたので、Hに移った。商で分類することをずっと考えていたが、それはO(N^2\sqrt N)になっていかにもまずそう。残り30分くらいで大幅に方針を転換した。冷静になると、Mの制限を外した問題がそのまま写像12相に存在する。玉も箱も区別せず、各箱に玉を1個以上入れるので、分割数P(n-k,k)というやつだ(ただし、コンテスト中は新しく箱を増やすときに玉を1個入れた状態で追加していたので、遷移が微妙に異なる)。全体に玉を追加したタイミングで、その後連続して箱をM+1回増やした場合の遷移先から前もって値を引いておくと、そこまで遷移していったときにうまいことvalidな状態のみを残すことができる。このことは、斜めに累積和を取りつつimos法を行っているとも理解することができるが、斜めに累積和を取るとか考えると頭を壊しがちなので、むしろ意識しないほうがうまくいくはず。

午後10時半からCFで何かのミラーコンテストがあったので、昨日と同じくICPCチームで参加した。結果はADBJGLIKHをこの順で通して9完。

Dashboard - COMPFEST 13 - Finals Online Mirror (Unrated, ICPC Rules, Teams Preferred) - Codeforces

Aから読み始めたが、Aが最も簡単な問題で、本当にこれでよいのかと首を傾げながら出したらFAだった。入力が106文字とちょっと怖いところだけが不安要素か。当時は気づいていなかったが、入力文字列がすべて同じ長さであるところから偶数番目の文字だけ反転する解法の正当性が簡単にチェックできる。Dは頑張って探索する感じの問題に見えるが、制約がギャグなので全探索できる。Bはどう見ても二分探索してくださいという見た目をしていて、その方針で考えた。適当にrを決め打った時にある点を含むような円は、原点から中心までの角度がある区間の内部に収まるという条件で表せる。この区間は円の交点の計算を流用すると求まる。そもそもどうやっても内部に含められない点をケアし忘れていて2WA。Jはチームメイトが通した。

このあたりでしばらく時間が空いて、100分ほど格闘してGが通った。最初の方針が、\sum_{i,j}\sum_{k,l}\gcd(a_i,a_j)\gcd(k,l)を求めた後うまいこと引き算して(i,j)=(k,l)なる場合のみ残すという方法だったが、これは結局iを固定してj\lt lに対して和を求めるような形が出現し、gcdを分離することができなかった。方針を大きく切り替える。ある数列\{b_n\}が与えられたとき、数列の要素の約数をそれぞれカウントしておくことで、値xに対して\sum\gcd(b_n,x)を求めるのを包除原理を用いてO(d(x)^2)(ただしd(x)xの約数の個数)で行える。個数カウントではなくて適切な値を足しておけば、重み付きgcd和も求まるので、まず数列の添え字の各約数に対応させて値をvectorなどに溜め、vectorの各要素をxvectorそのものを\{b_n\}として上記の計算を実行し、得られたgcd和を重みとして再度添え字の方で重み付きgcd和を求めればよい。

これだと約数の個数の2乗が出てきて、105以下の最大の高度合成数が約数を130個近く持つため、TLEしてしまう。同じ値が出現する可能性のある場所はmapを使って結果を持っておいたり、そのmapを使っていた箇所を配列(と配列の値を書き換えたタイミングを記録する列)で置き換えたりしたが、まだ間に合わない。ここで、O(d(x)^2)の部分は、xの約数のペア(p,q)であってp\mid qなるものを考えていたので、そのペアを最初に列挙しておくことにしたら、2sec弱で通った。

しばらく時間が空いたので、順位表で人間向け問題が一目瞭然になっていた。まずLは、dp_iへの遷移元の条件がj\lt iかつa_j\lt a_iかつa_i-i\le a_j-jと書ける。ここでa_iがpairwise distinctだとすると、a_iの昇順にiを見ていけばa_i-i\le a_j-jからi-j\ge a_i-a_j\gt 0が導けるため、j\lt iという条件を考えなくてよくなる。このことはpairwise distinctでなくても(a_i,-i)の昇順にソートすることで同様のことが言えて、a_i-iをセグ木のインデックスにすれば実家dpができる。方針だけ示して、実装はチームメイトに投げた。

次にI。\max(|a_x+a_y|,|a_x-a_y|)という式を分解すると|a_x|+|a_y|になったので、ほとんどギャグみたいなもの。更新はオイラーツアーして部分木に対する区間加算で行える。更新後に重みの配列を更新しわすれて1WA。このあたりでKの考察が完了していたので、マスがぴったり重なるコーナーケースを指摘しつつ見守っていたら通った。Hも思ったより簡単で、部分文字列bを受理するオートマトン上でdpするいつものやつ。Aho-Corasickのfailure関数みたいなものを計算する必要があったが、制約が小さいので愚直にやっても間に合う。

そのあとはE問題を考えていたが、パスのコストを単純に辺の本数で定めた場合の問題すら解けず厳しい。終了間際にC問題の解法っぽいものがチームメイトから出てきたが、実装する時間がないなあとなって終わってしまった。E問題は重心分解らしい。さすがにこの段階で未履修なのはまずいか。

ABCに戻ってコードゴルフをする。A問題はコンテスト中のdcコードでよい。B問題はPerlで文字列のxorを取る解を提出していたのだが、print関数ではなくprintf関数を使っており、そこで1B短縮されていた。さすがに呆れかえった。Cは文字ごとに分解して降順ソートし、2数の小さいほうの末尾に貪欲にくっつけるとよいらしい。Vimの48B解がすでに存在しており、Perlで同じく48Bに至ったがそこからは縮まない。Vimのほうで考えて、文字ごとに分解した後各行の末尾に文字列を挿入している部分を置換コマンドで一気に行ってみたところ縮んだ。DはPerl解をちょっと縮めたところすぐ取り返された。区間の始点と終点を区別する必要があって、Perlでは文字列に空白や改行が含まれているかどうかをチェックしているが、ほかの言語で実装しようとすると新たに別のデータを持つ必要があって難しそう。

このあたりでABC-Gを通した。kyopro-friendsさんのツイートを参考にして解いていたが、全然TLEが取れない。仕方なく公式解説を見たら、bitset<3600001>を2001本持ちますと書いてあってひっくり返った。僕の実装でも、縦と横を同時に復元するようにしたら通った。定数倍2分の1が効きすぎている。その後bitsetを大量に持つ解法でも通しておいた。

コードゴルフを続ける。EFは飛ばして、Gを縮めた。Ruby多倍長整数をbitsetのように扱うと、必要なだけのメモリしか確保されないので軽め。C++で書くより速くてびっくりした。しばらくチマチマ縮めて167B。文字列"Yes"と復元した解を出力するのに、sumメソッドの引数に"Yes\n"を指定すると縮んだのが面白かった。Hは当時の最短を単純にCrystalで書き直しただけ。熨斗袋さんのユーザ解説と同じ遷移で、実のところ僕のコンテスト中の解法とも、貰うdpと配るdpの違いだけでほぼ一緒のようだ。

さらにABC前にatgolferに流れてきていた更新もいくつか取り返した。Rubyである非負整数の変数iが0に等しいとき0、そうでないとき1を得るのは、これまで-2[i]を使っていたが、負号が付くことを許容すればi/~iでも計算できる。これでさらに2問ばかり縮めることができた。

そんなことをしているうちに昼前になってしまった。来週木曜日に迫った4年ゼミに向けて、しばらく前学期の最後のほうの発表を復習していた。正午を回ってから布団に入り、ラノベを1冊読了。

VTuberなんだが配信切り忘れたら伝説になってた」2巻。今巻は前にもまして例のアレのネタや下ネタ・コピペ・パロディが盛りだくさんで、ちょっと正気では読んでいられない。しかし作中世界にどっぷり浸かると面白く読めた。特にシリアスなシーンが多かったりするわけではなく、正直シリーズとしての内容はあまり覚えていないが、読後感がまったりしていて非常に良かった。後書きで、次巻にはweb版で屈指の人気を誇ったシーンが収録される、ということが書かれていた。気になる。今すぐweb版を読みに行きたいところだが、ぐっとこらえて3巻の発売を待ちたい。かなり売れているらしく、続刊することはほぼ確実らしい。

10/03(日)午後2時半就寝。

10/03(日)

午後6時起床。第8回PASTの過去問が公開されるかもと思って1時間おきに起床して確認していたのだが、その時にDMでSUSURUがゆゆうたとコラボしてやばいクレーマーのSUSURU TVを歌ったことを知り、飛び起きた。

ゆゆうたからツイートされたほうの曲(特にラストのフレーズ)、ほとんどSuper Driverに聞こえる……。勢いの良い曲調が共通しているが、それに加えてコード進行とやらも同じだったりするのだろうか。

しばらくコードゴルフをした後、昨日の続きで4年ゼミの発表の復習をしていたが、また途中で切り上げて午後11時半からCF #746 div.2に出た。

Dashboard - Codeforces Round #746 (Div. 2) - Codeforces

F1までの6完。Aは大きなほうから2つ取って交互に使うのが明らかに良い。Bは両端からそれぞれn-x要素を自由に並べ替えられるので、その範囲が数列全体を覆っていれば良いし、そうでなくても、実際にその部分だけでソートしたら全体が揃うような場合も良い。Cは、適当に分解した結果の連結成分3つを、全体のXORを変えずに纏めることができるので、分解するのは2つか3つであるとしても良い。2つの場合は簡単で、木全体のXORが0ならば(またその時に限り)適当に1頂点抜けば達成できる。そうでない場合は、分解した各連結成分のXORが定まるため、木全体から2つ抜けるかをチェック。切る辺2本の片方がもう片方の祖先になっている場合は注意が必要。ちょっとした木DPを行ったが、帰りがけ順に頂点を見てXORを計算しつつ切り離していくと処理がまとめられて簡単そう。

Dは、どこかの辺が答えになるとしてよい。辺全体を半分に分けていった。分けるときは、現在残っている辺からできるだけ連結になるように選び、選んだ辺たちに含まれる頂点を聞く。その中に答えと一致するものがあればよいし、なければ以降選ばなかった辺たちを聞くときに今聞いた辺の情報が邪魔になることがない。木の辺をdfs順に並べて二分探索という解法を見たが、結局それも今言った「できるだけ連結になるように選ぶ」を満たそうとしているという理解でよさそう。Eは、まず区間の長さが偶数でなければならないことがわかる。そのときANDで残るbitを決め打つと、それ以上のbitは全部XORで消える、つまり偶数個なければならない。これはZero-Sum Rangesの要領で累積XORを持っておけば求まる。ANDで残るbitも含めてキーにすれば、区間の長さが偶数であるという条件も同様に書けるため、楽。mapを書き換えるのは計算量が悪化してまずいので、配列とそれを書き換えたタイミングを持って頑張る。このテクは昨日のCF 5hでも使った。

F1は、左下と右上の操作は左上の操作2回で再現できるため考えなくてよい。右下の操作は高々1回しか行わないようなので、それを全探索して、残り左上の操作は貪欲に決めてよい。隣り合うマスが異なるかどうかを持っておくと、右下の操作では1列の高々O(n)箇所しか変更しないので、差分の計算もO(n)で行えて全体で3乗になる。実装を安全側に倒してそこそこ定数倍の大きなコードを書いたら1300msくらいで怖かったが、通った。F2も左上と右下の操作しか考えなくてよいことは同じだったが、右下の操作が何回も行われる可能性があって、それを最適に選べなくて解けなかった。僕は「隣り合うマスが異なるかどうか」を見ながら計算しようとしたのだが、それよりも「どこのマスを右下にして操作するか」を最初の状態で求めて、これを適切に右下の操作で置き換えることを考えるのがよかったらしい。この見方の元、二部グラフの最大マッチングに落ちるようだ。

水曜日にAtCoderProblemsに出した、ゲノコン2021をクロールするようにするプルリクがマージされたので、atgolferのほうも対応させておいた。

add genocon2021 by kotatsugame · Pull Request #21 · kmyk/atgolfer · GitHub

また4年ゼミの復習の続きをして、今度こそ最後の発表まで読み終わった。次回自分が発表する番なので、担当することになる箇所を読んで式変形を追っていたのだが、埋まらない行間を1か所見つけてしまった。教科書を見返しても、まだ証明されていない事実を使っているように見える。今読んでいる章では素数定理と同値な命題を大量に示したのだが、素数定理そのものはまだ全然示していないため、使って良い命題とそうでない命題を慎重に区別する必要があった。

考え込んでいるうちに椅子の上で意識を飛ばしてしまったらしい。ふと気づくと時間が1時間くらい飛んでおり、変な体勢だったので首が痛いし、寝ながら舌を噛んでいたらしくそこも痛い。満身創痍で布団に潜り込み、改めて就寝。午前4時半だった。

そういえば、第8回PASTの過去問は(この部分を書いている2021/10/04(月)午後3時時点で)まだ公開されていない。

週記(2021/09/20-2021/09/26)

09/20(月)

先週の週記を投稿してからの話。まずECR22の続き(EF)を解こうとした。F問題は諦めたが、E問題について。

Problem - E - Codeforces

全然解けない。しばらく唸って、このレベル帯の問題を取っておく必要性は薄いと考え、諦めて解説を読むことにした。ある要素を取る条件は、それと同じタイプの要素であってk個前にあるもののインデックスを見て、現在処理している区間より左側にあるかどうか、と言える。この言いかえをすると、求める要素の個数は「ある区間内のある値未満の要素の個数」とできて、ソートされた区間を持つセグメント木で数えられる。自分はrangefreqというライブラリにしていた。

次にECR23を埋めた。

Dashboard - Educational Codeforces Round 23 - Codeforces

Aはよい。Bは場合分け祭りかと思ったが、ちゃんと整理するとそうでもなかった。Cは難しかったが、問題タグに二分探索とあるのが見えて、その方向で考えてみると非自明に感じられる単調性が見つかった。興奮してコーディングしたらlong longのつもりでlongと書いてしまい、CFでlongは32bit整数なのでWA。昔一度やらかしてからは常に意識していたので、引っかかったのはかなり久しぶり。Dはmaxとminそれぞれの和が計算できて、答えがその差として表せる。EはBinaryTrieのverify用問題。Fは区間の端だけ取り出し、遅延セグメント木に0と1の個数を持ちたい。実際には個数を持つ必要はなく、0・1が存在するかしないかをboolで持つだけでよい。作用素が微妙に準同型になっていない(単位元で壊れている)気がするが、幅0の区間に作用させることは考えなくていいのか、通った。

布団に移動してハーメルンを少し読み、午前11時半に寝落ちした。

僕の主観において月曜日は消滅したが、実際はこの後日付が変わる前に一度起きている。その時のことは火曜日の欄に書いた。

09/21(火)

09/20(月)午後9時くらいに少し目を覚まし、ハーメルンを読み進め、1作読了。「無自覚な吸血鬼の王」。勘違い物を目指していたのだろうけど、よくわからないなあという感じ。主人公の能力・来歴はその多くが謎のままエタってしまっている。また主人公のキャラもあまりに悲観的に感じられて好みではなかった。

syosetu.org

また別のハーメルンを開いて少し読んだところで再度就寝。次に日付が変わって、09/21(火)午前2時くらいに目を覚ました。

さらにハーメルンを読み進め、午前4時くらいに1作読了。「東方神零録」。主人公のノリがキツいが、直球でハーレムを作っているのが目新しかった。東方は女性キャラが多く、二次創作でオリ主が複数のキャラから好意を寄せられているのはよく見るが、実際に(それも複数と)深い仲になる作品は限られている気がする。

syosetu.org

もう1作読み始め、適当に斜め読みして1時間ちょっとで読了。「東方創造伝」。何らかの評価を下せるほど話が進んでいない。

syosetu.org

東方オリ主古代スタートのほとんどは、最初にオリ主が古代都市の近くに降り立って八意永琳と出会う。それで、しばらく古代都市で生活するのが定番の流れなのだが、正直古代都市の描写にはほとんど興味がない。月に移住してからは竹取物語の時代まで出てこないし、出てきたとしてもキャラクターだけで、古代都市自体は完全に消滅して現代に続く文明には一切関わらないからだ。

午前6時くらいになって布団から脱出した。食事して午前7時からインターンの業務に手を付ける。以前書いたコードは途中でエラーを吐いていたが、その原因となった自分の勘違いを1on1で修正してもらっていたので、コードを書き直す。一度書き始めたらこっちのもので、パパっとやって3時間くらいで一通りの完成を見た。完成というのは、プログラムが最後まで動いているということ。これで今日の午後に予定されている1on1で報告する内容には困らないだろう。1on1駆動開発……。

書いたコードは現在GPUを使用して動いている。試しにCPUで動かしてみたところ、思っていたより何十倍も遅くてびっくりした。こんなに違いがあるのなら、それはインターン先もわざわざPCを送ってくれるというものだ。

ICPC国内予選の競技ルールが発表されていたことを知った。今年はチーム3人がそれぞれ個室から参加しなければならないらしく、びっくり。でもサークルとして参加場所を確保する必要がなくなるから、その点楽にはなるのかもしれない。まあもともとサークルとして参加場所を確保する必要はないのだが、個人的な思想として3人集まって出てほしいというものがあり、それをサークルメンバーに押し付けるならば、義務として参加場所は確保しておかなければならなかった。

2021 国内予選 特別競技ルール | ICPC 2021 Asia Yokohama Regional

ECR24を開いて少し解き進めた。とりあえずA-Dまでを埋めた。

Dashboard - Educational Codeforces Round 24 - Codeforces

Aは算数。Bはやるだけだが、うっかりミスで1WA。Cはsolvedが少ないのを見て身構えていたが、実装がややこしいだけでアルゴリズム的には普通の累積和。4方向それぞれ計算するときの和を累積させる向きとか、ドミノが横に置かれているか縦に置かれているかでコードを変えなければならないとか、面倒さはピカ一だったが、一発で通ってうれしい。

Dは一見してわからなかったが、出かけようとシャワーを浴びていたら思いついた。すべての色について調べても、計算量は全体の要素数で抑えられる。

先週金曜日の日記にも書いていたが、入学意思確認書の提出期限が明日に迫っている。今日提出しに行くことにした。

大学院に合格したはいいものの、入学意思確認書を提出できていない。今週はもう終わってしまった。期限は09/22(水)である。火曜日あたり徹夜して直接教務課に出しに行きたい。

週記(2021/09/13-2021/09/19) - kotatsugameの日記

原付に乗って山に登る。教務課にたどり着いたのが午後1時ちょっと前だったが、その時間帯はちょうどお昼休みだった。仕方がないので食堂で食事した後、ハーメルンを読んでしばらく時間を潰す。ベンチに座っていたら目の前に鳥のフンを落とされてびっくりした。危なかった。

問題なく提出完了。これで本当に大学院への進学が決定したと言える。山を下り、川内キャンパスの生協に行って先週水曜日に注文していたラノベを受け取り、散髪して家に帰った。散髪の間はほとんど意識を失っていたが、時たま頭を起こすよう促されたことを覚えている。

注文したのは6冊で、うち1冊は在庫がなく、取り寄せている最中らしい。それにしてもまだ入荷連絡の音沙汰がないとはびっくり。重版待ちだろうか。

ECR24の続きを解く。今回はEからGまでちゃんと通せた。

Dashboard - Educational Codeforces Round 24 - Codeforces

Eは素因数ごとに尺取り法をする。初期値を間違えていて1WA。Fは何を思ったか、「辺の半分以上が橋」を「頂点数の半分より多く橋が存在する」だと思っていてO(1)算数をしてしまい、1WA。すぐ二分探索に直して通したが、問題タグを見てしまったのが効いているかもしれない。

Gも問題タグを見たのが効いていて、フローを流した。これはECR22-Dの強化版。ECR22-Dはdpでも解けたが、問題タグにフローがあるのにびっくりしていたのを覚えている。今回の問題はフローでないと解けない。

Dは2つの部分列を作るのに、現在見ている要素が先頭になっていないほうの部分列の先頭を持っておくdp。問題タグにflowと書いてあってびっくりした。

週記(2021/09/13-2021/09/19) - kotatsugameの日記

ECR25のA-Dを通した。

Dashboard - Educational Codeforces Round 25 - Codeforces

Aからコーナーケースに引っかかってキレていた。与えられた文字列の末尾が0だと、さらに1桁0が送られていると見なさなければならなかった。Bは実装するだけだが、左下方向の斜めをすっかり忘れていて1WA。CDは貪欲。Eも適当に貪欲しようとしたが、2回ほど嘘解法を投げて、結局わかっていないまま放置している。

午後5時からインターンのメンターさんと1on1。今日の朝やったことを話して、この先数日やることを決めた。また働き方に関して、1on1がないとサボりがちになってしまうので、頻度を増やしたいということをお願いした。1on1が終わってから、微妙にやる気がある今コーディングするべきだと感じ、しばらくバリバリコーディングしていたら、次回までにやることとして設定したものが完成してしまったので、慌てて明日にも1on1をお願いした。

新サークル長から、コロナ禍前の活動がどのようなものだったかについて質問を受けた。確かに彼は今大学2年生で、入部時点で全ての活動がオンラインになっていたのだ。個人的には、僕がサークル長になってから対面で活動していた時期はずっともくもく会と称して本当に黙ってコーディングしていただけだったので、オンラインの活動に移行してからは内容も充実したし、教室の予約の手間もなくなって良かったなと考えていたのだが、それはそれとして対面で活動していた文化が今まさに喪われようとしていることに気づき、愕然とした。

しばらくパソコンの前に座っていたが、眠気がひどくて椅子の上で意識を飛ばしてしまったので、布団に移動して就寝。午後11時だった。

09/22(水)

午前4時くらいに一瞬起きたが、ちゃんとすぐに寝なおすことに成功した。次に、午前6時半くらいに目を覚ます。今度は二度寝できなかった。しばらくハーメルンを読んでいて、午前9時くらいに布団から出た。

ちょっとコードゴルフをした後、最短コードを収集するクローラーを久しぶりに動かすことにしたが、動かない。調べてみたところ、AtCoderProblemsのAPIが変わっていて、個人の提出を全件取得するAPIが無効になり、代わりにある時刻から500件分を取得するAPIが提供されるようになったらしい。

適当にコードを書き直す。提出を全件取得するのに、時刻0を指定して取得→取得できた最後の提出の1秒後からまた取得→……を繰り返すことにした。完全な同時刻に2つ提出があると壊れる可能性があるな、とは思っているが、必要なのはACしたことのある問題リストで、今のところは漏れなく検出できている。経過を出力してみると、どうやら僕の提出をすべて取得するためにはこのAPIを103回叩かなければならないようだ。スクリプトを起動するたびにそのようなことをしているとまずいから、ファイルに書き出しておくべきかもしれない。

昼前に家を出て、大学生協で買い物をし、ゲーセンに行った。今日は3時間くらいプレイした。なかなかいい成果が出た。

まず新しく解禁した曲について。12+、13、13+をそれぞれ1曲ずつ解禁し、12+と13ではAJを、13+ではSSSを出した。特に13+のSSSは(何度も譜面動画を見ていたということもあり)初プレイで達成できた。記憶にある限りでは、13+の初プレイでSSSというのは今日が初めてな気がする。これはAJも狙えるのではないかと思ってもう何回かプレイしたが、結局初プレイのスコアすら超えられなかったのは残念。初見プレイが微妙に上手いというのは音ゲーあるある。

また、HAELEQUINでSSSを出した。これで13+の未SSSは3譜面になった。先週水曜日の時点で敷地帯の運指さえ組めれば出ると言っていたが、実際そのようになった。肝心の運指は餡蜜で、SSSを出したプレイではそれ以前もめちゃくちゃ上手く行き、敷地帯直前で1-0、敷地帯抜けて3-0。今日は最後の変なリズムの交互が下手くそで、案の定1-1出してしまったが、それまでが望外に上手かったので耐えた。

今日プレイした感じでは、敷地帯の運指をちゃんと組むことがSSSを出すことの(必要かつ)十分な条件だろう。

週記(2021/09/13-2021/09/19) - kotatsugameの日記

他に、初音ミクの激唱でAJを出した。13+のAJは2譜面目だが、狙って出したという意味では初めての経験。かなり前に1-0を出してから、ほとんど噛み合い待ちの様相ではあったが、13+のAJに対する現実感がなく、今日まで本気で狙うプレイをしたことはなかった。3ヶ月くらい前に13+のAJがポロッと出たので、今日念入りにやってみることにした。

13+のほうもSSS出しておくか、と思って詰めていたら、なんと一気にAJが出てしまった。13+ではこれが初めてとなる。

週記(2021/06/14-2021/06/20) - kotatsugameの日記

実際、譜面の中で押せない部分はなく、安定しなかった鍵盤も入りの配置を覚えたらほぼほぼ通るようになった。今日詰めている間に一度99精度も出たのだが、AJ時のプレイでは安定を取って縦連を擦ってしまったこともあり、赤はそこそこ出ている。それでも堂々13+の最高スコアであった。

帰宅して急いでシャワーを浴び、午後4時から1on1。昨日コーディングした内容を報告し、微妙に出ていたエラーを解消してもらったり、その結果見つかったバグを直したりした後、さらにやることを決めた。午後5時からはミーティングで、今週も何事もなく終了。

大学生協で本を10冊注文した。新刊のチェック漏れがあって、2回に分けて注文してしまったが、支払いなどは結局のところ大学生協の店舗で行うので、特に損しているわけではない。しかしなぜチェック漏れが発生したのかが謎。漏れた新刊も発売されることは認識していたので、どこかでもう買ってしまったのではないかと購入記録を確認したりしていた。

溜めていた日記を書いた。火曜日の欄にICPC国内予選の競技ルールの話を書いたが、チーム3人がそれぞれ個室から参加しなければならないという文面が消えており、前年と同じく集まっても集まらなくてもよいとされていてびっくりした。

2021 国内予選 特別競技ルール | ICPC 2021 Asia Yokohama Regional

日記を書き終えてからパソコンを弄っていたら、椅子の上で意識を飛ばしてしまった。急いで布団に移動し、就寝のツイートをする。しかし微妙に目が冴えて眠れない。スマホを触って、Twitterで流れてきた「Vtuberの姉はオンラインで生きている」というnote記事を読みふけってしまった。

Vtuberの姉はオンラインで生きている|しじみ|note

ところどころにドキッとする言及がある。家にお金を入れないとか、母の日にプレゼントを用意しないとか。特に、僕が親にプレゼントを贈ったことがないことを思い出し、いたたまれない気持ちになった。せっかくインターンを始めたのだし、9月の給料が入ったら何かすることを考えたい。親に諮ってみよう。

日付が変わったあたりになって、決心してスマホを手放し、積極的な睡眠を試みたところ、意識を落とすことに成功した。

09/23(木)

午前5時すぎくらいに目を覚ます。TLにPixiv小説が流れてきて、それを少し見た後勢いに任せてほかのものを色々読み漁っているうちに、眠気がすっかり消えてしまった。ちなみに、主に「転生したらスライムだった件」のリムル愛されSSを読んでいた。

通知が行かない引用ツイートについて。以前まで、ツイートのリンクをコピーした後、URLのユーザーIDの部分を別の文字列に変えてツイートの文面に含めることで、本人に通知が飛ばないまま引用ツイートができるという仕様だったが、いつの間にか使えなくなっていた。そのあとどこかで、ユーザーIDの先頭に@をつけるといいらしいと聞いたので、試していた。kotatsugame_tのアカウントからatgolferのツイートをそのように引用して、atgolferから確認すると、確かに通知は来ていないようだ。しかしツイートのプレビューも表示されないため、引用ツイートとしては片手落ち。

atgolferに久々にログインしたので、ちょっとbotの運用について考えた。具体的には、botからフォローを飛ばすべきか否か。僕はkotatsugame_tのフォロー方針、つまりフォロバ100%を第一義としているので、フォローを返さないのは何となくむず痒い気持ちになるが、一方atgolferを作ったkimiyukiさんにはその方向のこだわりはなさそう。しかし以前から5フォローだけしてあったのがどうにも中途半端に思えて気になっていたので、少しだけ増やすことにした。フォロワー欄を見て、僕がatgolferで名前を見かけた覚えのある人をフォロバした。僕としてはこれで運用方針の統一性があると思えてスッキリ。

今日は午後1時からACPC2021 day1があるが、それまでしばらく時間が空いた。微妙に眠気が出てきたので、眠らないようにラノベを1冊読んだ。「お見合いしたくなかったので、無理難題な条件をつけたら同級生が来た件について」2巻。1巻から少し時間が空いたので話の内容を一切覚えておらず、当時の日記から復元しようと思ったが、設定に関する違和感しか書かれておらずちょっと困った。思えば、日記に本の感想をある程度細かく書くようになったのはそこそこ最近だったかもしれない。

登場人物が軒並み名家の御曹司・令嬢だった

週記(2020/11/30-2020/12/06) - kotatsugameの日記

ただ、1巻の内容をあまり覚えていなくても面白かった。特に、上で引用したように1巻の感想で触れていた設定に関する違和感が解消された。どうやら身分差のある恋を描いているらしい。そういうテーマは童話などではよく聞くが、現代社会を舞台にしたラノベで取り扱おうとすると、登場人物が軒並み上流階級の人間になってしまうのだろう。目新しくて面白い。また合間合間に挟まるやけに不穏な別視点の文章も楽しめたが、受け取り方は読むときの精神状態によりそう。2巻では主人公とヒロインがかなり近づき、いわゆる両片思いになっていると考えられる。その状態は健康にいいが、ここで身分差が火を吹くらしい。3巻が怖いが、楽しみでもある。

↓このツイートは2巻の文章の一部について。

午後1時になって、ACPC2021 day1にソロで参加した。結果は8完4位、個人勢としては2位のはず。説いた順番はABDFGHECなので、その順に感想を書く。

https://onlinejudge.u-aizu.ac.jp/services/room.html#ACPC2021Day1

Aは、Tの分割方法を全探索して、各行で揃った部分を持つbitDPをした。解説の方法がシンプルでびっくりした。Bは319を気合で通す。部分集合を全部舐めるときに、最上位bitだけ取り除いておくとループ回数が半分になることを利用した。ループが足りず1WAしたが、FAだった。OR畳み込みを条件を満たすまで繰り返すのが想定解らしい。Dは、部分集合の全域木の個数をそれぞれ行列木定理で求めておいて(bitDPでなんとかできるかと思ったが、できなかった)、あとは3つの市に分けるのをまた3^Nで行う。市をまたぐ道路をカウントするのにNかけるとまずいと思ったので、頑張ってO(1)で引けるようにした。1つの市を取り出すのは2^Nでできて、そのループ内で別に部分集合を渡るループを回し、部分集合からさらに1要素を抜いた時の値を用いて現在の部分集合の値を計算する。実際にはNかけてもよかったらしい。

Fはパッと見難しい。前から貪欲かな~など思ったりしたが、よくわからない。しかしこの時点で一番solvedが多いということで、ボンヤリとあれこれ考えていたら、ふと操作2が可逆であることに気づいた。なので、最初に操作2を行えるだけしてよくて、得られた文字列の部分列としてTが含まれるかを見ればよい。含まれる場合は当然一致させられて、含まれない場合は、もうこれ以上文字を増やすことができないため不可能。Gは2つのパスとみて、2つの端点を2次元dpのキーにするやつ。復元が要求されていてキレそうになりながら書き直した。

Hは、最初に辞書順を考えずカウントして、後からS未満とTより大をそれぞれ取り除いた。よく問題文を見るとS\le Tとは書いていなかったので僕の提出は落とせそう。取り除き方は、Tを考えているときは文字の辞書順を逆転させることで、両方「未満」として扱える。計算についても、例えば先頭文字で大小が決まらない場合は次の文字……と見ていくと、どの文字を選ぶかはだんだん固定されざるを得なくなっていくので、線形時間で計算できる。Eは\sqrt{-1}が存在するような素数Pを選び、(x,x\sqrt{-1})(x\sqrt{-1},-x)を入れていくことで、値の積和についての条件は満たせる。あとはこのペアを9個作れば29=512本の数列ができて、答えの1つとなる。

Cは結構最初のほうに読んで不可能だと諦めたのだが、コンテストが2時間も経過してみたらかなり通されていた。読んでみると、M\le Nであることに気づいた。つまりグラフが木かなもりの場合しか考えなくてよいということで、どうとでもなる。M\le\min\left(\frac{N(N-1)}2,N\right)と書かれると、途中まで読んだ段階で2\times 10^5とminを取っていると自分の頭が勝手に補完してしまうので、惑わされた。残り時間はIを考えながらTwitterを見ていた。30NQでは解けた気になったが、定数倍が重すぎて通らないだろう。解説を読んだ感じ、30NQの考察も間違っていそうな気がする。

ECR25のEFを解いた。Gは放置。

Dashboard - Educational Codeforces Round 25 - Codeforces

Eはちょっと前から開いて数度考えていた問題。辞書順最小を求めるので当然前から貪欲だと思っていたが、正しく求めようとすると計算量が抑えられない。試しに後ろから貪欲を考えてみると、辞書順最小が得られることが示せてしまった。ちょっと前のABCで後ろから貪欲する辞書順最小の問題があった気がするが、その時一般には成り立たないことが何度も言及されていて、それで後ろから見ることに恐怖心を抱いていたのかもしれない。FはZ-algorithmとdpで、dpの遷移先を決めようとループするとO(1)では遷移のコストを求められないが、遷移に使う部分文字列を決定して遷移先を2回以上見ないようにすると計算量が落ちる。

あまりにも眠いので午後6時くらいに布団に倒れこみ、そのまま6時間も昼寝をしてしまった。起きた時には日付が変わろうとしていた。

ECR26のA-Fを解いた。Gはこれまた放置。

Dashboard - Educational Codeforces Round 26 - Codeforces

Aはよい。Bは3つの文字が異なることをチェックしておらず1WA。Cはif文を書きまくる。Dはbool値dpを考えてしばらく悩んでいたが、元の次元を1つdpの値に入れるとよい。最大値を保存する。Eは、f再帰的に呼び出されるごとに\gcd(a,b)が小さくならないことがわかるが、実装には特に関係ない。x素因数分解して、今以降で最初に\gcd(a,b)\gt 1となるまでの操作回数を計算する。1回でyは必ず半分以下になるので、計算量的に十分間に合う。Fは、まず先頭の0を全部取り除き、残りの数列の長さが4以上の場合はシミュレーション。2と3の場合は、値を式で表して二分探索なりする。

次にECR35のFGを解いた。このコンテストは僕が4年近く前にリアルタイムで出たもので、upsolveをしていないためFGが残っていた。

Dashboard - Educational Codeforces Round 35 (Rated for Div. 2) - Codeforces

Fは難しいが、適当に直径を取ってみたら解けた。直径を残すように葉を削除していくと、すべての葉が最大の長さで削除できるため、よい。Gは置換の様子をarray<short,100>で持ったら2995msで通った。高速入出力を貼って遅延セグ木から双対セグ木に切り替えると1060ms。解説を読むと、普通のセグ木に置換の合成を乗せて、クエリをソートして端から見ていくことで毎回全部の置換の合成が得られるということらしいが、実装したら1169msだった。

以上でCFにおけるここ1年間のAC数が1000に到達した。最近はこれを目指していたため、達成した今何をするべきかがわからない。

TwitterVSCodeのデバッガの導入ができないというツイートが流れてきたので、VSCodeをほとんど使ったことがないくせに首を突っ込んでみた。最初はTwitterのリプライでやり取りを交わしていたが、途中からさすがに面倒になってGoogle Meetで画面共有してもらいながら進めた。サークルメンバーなのでその辺りの障壁は低いはず。

どうやらQiitaの記事から拾ってきた設定ファイルがWSL向けに書かれている一方で、環境がWindowsのままらしい。いろいろ調べてみたが、結局Remote WSLを導入してもらうことになった。Qiitaの記事ではSSHログインだのなんだの書いてあるが、特に必要はなさそう。というのも、結局WindowsディレクトリとWSLを連携させようとするから小難しいことをしなければならないのであって、最初から全部WSL側でやってしまえば特に問題ない。これまで書いてきたコード辺をエクスプローラ経由でコピーしてもらい、あとはターミナルで良しなに操作してもらうことになる。デバッガ起動についての設定も、ACLのインクルードのために毎回-Iオプションを渡すことさえファイルに書いておけば、Qiitaの記事からコピペしてくるまでもなかった。これで動くようになって一安心。自動で生成されたファイルはできるだけいじらないのが一番良いと思っている。

ラノベを1冊読んだ。「神々の権能を操りし者」。自分の実力を隠している主人公という前フリが琴線に触れたので購入した。1巻から実力を周囲に知らしめていて、手っ取り早い満足感があった。しかし2巻以降はどういう展開になるのだろうか。なろう原作で、なろうのほうではもう文庫数巻分連載されていそうだが、そちらを読むほど気に入ったわけではなかった。

別のラノベに手を出そうとしたが、明日は夕方から1on1があるし、そもそも何も進捗が産めていなくてまずい。焦りながら午前10時、就寝。

09/24(金)

午後2時起床。昨日シャワーを浴びずに寝たせいか頭皮が痒くて仕方ない。急いでシャワーを浴びた。原付に乗って購買に行き、注文した本を受け取った。今週火曜日の日記で言及した、届いていなかった1冊。重版待ちだろうかと書いたが、確認すると初版だった。

帰ってきてから1on1まではコーディング。最低限の進捗を産んで、何とか報告する内容ができた。最近、悪い意味で1on1に慣れてきたのか、報告と称して特に纏まっていないことをグチャグチャ喋っているだけになってしまった気がする。他の人の1on1を録画で見てみるべきなのかもしれない。少なくとも、今の報告の形態は、相手への甘えが多分に含まれていたと自省している。ともあれ進捗は進捗で、この先やることもこれまでと変わらず決めることができた。今日はあっさり目に終了。

自分の評価しているラノベの続刊が出るのかどうかを常々気にしていた。今日、BOOK☆WALKERというサイトにラノベランキングが日間・週間・月間で出ているのを見つけた。ここは判断の要素として十分だろう。ちょっと眺めていたが、精霊幻想記の既刊が軒並みランクインしていてびっくりした。アニメ化・ソシャゲ化はかなり広告効果があったということだろうか。個人的には、ニコニコ動画で出てくる謎解き風広告の答えがキャラクター名なのはまずいんじゃないかと思っている。そんな固有名詞を答えにするのは、ダメだろ。

bookwalker.jp

しばらくラノベを読んでいたが、午後9時20分からyukicoder 315に出た。全完。

yukicoder contest 315 - yukicoder

Aはよい。Bは得点がiであるという部分をちょっと誤読して時間を取られた。最適な戦略が常に同じだろうと予想していたがそんなことはない。CはDP、DはbitDP、EもbitDP。この3問はほとんど自明。Fは無限場合分けで、その時かなり眠かったのもあり厳しい思いをした。幸い一発で漏れなくパターンを列挙することはできていたようで、あとは場合の数や係数を修正していたらサンプルが合い、通った。特に、一番最初の実行からサンプル1でほとんど正解の値が出たのがやる気に繋がった。

「クラスの大嫌いな女子と結婚することになった。」3巻を読んだ。非常に面白かった。テンポのいい掛け合いが小気味よいと思っていたが、もしかして漫画原作ということが関係しているのか?漫画は読まないので、どのくらいのペースでそういう掛け合い・ギャグが挟まるべきなのかを知らないが、とにかくラノベであまり見ない感じのテンポであることは確かだ。内容についても非常に満足感がある。2人がそれぞれ空回りしている様子は辛かったが、それらの描写があってこそラストシーンが光る。報われた気持ちになった。新キャラが出るようで4巻への引きは不穏だったが、楽しみ。

次に「転生ごときで逃げられるとでも、兄さん?」2巻を読んだ。めちゃくちゃ面白かった。紙城さんは、今のところ代表作「継母の連れ子が元カノだった」で恋愛もののイメージが強いが、個人的にはバトルシーンの爽快感や見せ場の作り方が好み。書籍化作品では他に「最強カップルのイチャイチャVRMMOライフ」もバトルシーンがあって好きだったが、こちらの続刊は……過去の売上ランキングを調べた感じ、望み薄か。そもそも著者がシリーズを複数抱えていて超多忙だろう。また、恋愛ものでもバトルものでも、ところどころにミステリのエッセンスが加わっていて、それがまた面白いのだ。今回の巻では特に学園・順位戦・闘技場でバトル、とテンプレ設定が余さず盛り込まれており、間違いのない面白さだった。

日記を書いてからちょっとコードゴルフをしようと思ったが、全然縮まない上に画面を見ているつもりでしばしば意識を飛ばしてしまったため、諦めて布団に入った。午前7時就寝。

09/25(土)

午後0時半起床。眠気と戦っているうちにACPC2021 day2が近づいてきてしまい、昼食のために用意したパックご飯やみそ汁を食べられないままコンテストに突入した。30分ちょっとして一段落した頃合いにようやく食べたが、冷えていて悲しい気持ちになった。その頃はコンテストでも冷えていたが、最終的には10完9位と、ギリギリ面目を施せた気になっている。順番はABCDEFGIKH。

https://onlinejudge.u-aizu.ac.jp/services/room.html#ACPC2021Day2

Aはよい。BはT_i\le 3000の制約からP_iも小さいものだけ考えてよいことを導くと、2次元dpができる。昨日に引き続きFAだった。Cは線分と点の距離を求めるだけなので幾何ライブラリにある……が、誤差が怖かったので整数の範囲で計算を行うライブラリを持ち出してみた。結果、verifyしていなくて式が違う上にオーバーフローしており、2WAしてC++で通すことを諦めてRubyを書いたが、typoでさらに1WA。合計3WAも出してしまった。聞いた話によると、どうやら普通にlong doubleで通るらしい。何のための問題だったんだ……。DはA_iでソートして実家dpをした。

Eは難しかった。タイプ1のクエリはオイラーのφ関数そのまま。タイプ2が問題だった。結局、1\le Z\le NX_iと互いに素なものを求めてφ関数の値を引くことにした。互いに素なものを求めるのは、square-freeにして包除でできる。計算量が怖かったのでメモ化しておいた。Fは二分探索やるだけ。Gは木でk個上の祖先が欲しくなったが、これはdfsで潜るたびにvectorにpushして、上がるたびにpopすると得られる祖先リストで求まる。Iは同じ人を含むサークル同士に辺を張ると重み付き最大安定集合になり、半分全列挙で解ける。

Kは腕前をどれだけ上げるかを決め打つという発想で、まず各ステージについて手動でクリアするレベルとそれに必要な腕前を計算しておき、腕前の値で降順ソートして、どのパターンでクリアするかを変化させながら計算する。これは優先度付きキューに入れて、腕前をだんだん落としつつ足りなくなったらパターンを切り替えるという方法でシミュレートできる。Hは2次元セグメント木で、0の処理が怖かったので書き換えた場所の4近傍も構築するようにしたら2.79secで通った。実装は↓のページを参考にしたが、updateの時にちゃんと下2つの値を見るように書き足す必要があった。

blog.hamayanhamayan.com

今日はCodeChefのコンテストがあるらしい。先週気になっていると言ったばっかりだし、また今日はコンテスト尽くしの1日にしてみようという思いから、アカウントを作った。練習問題を3問ばかり解いて、どんな感じなのかを探る。main関数の型がなくてもCEにはならず、longは64bit整数らしい。

最近いろんな人がCodechefに出るようになっている。最初出会ったときに謎インドコンだと思って敬遠したっきりなのだが、やっぱり自分が出ていないコンテストがあるとちょっと焦燥感がある。今からでも始めるべきかもしれない。

週記(2021/09/13-2021/09/19) - kotatsugameの日記

新しいラノベを読み始めたが、そこそこで置いておいて、先に食事やシャワーを済ませておくことにした。今日は朝の5時までコンテストがあって、次の日の午後1時からもまたコンテストがあるからだ。

午後8時になって、ARC127に出た。ギリギリで5完して24位。

AtCoder Regular Contest 127 - AtCoder

Aは1,11,111\dotsそれぞれについて数える。数える方法もちょっと考え込んだが、桁を決め打てばそれぞれ単純なminで求まる。Bは難しい。tの先頭1文字が2であることは確定する。そのあとはできるだけ0を置きたいので、N\le 3^kなるk\ge 1を取って、後ろk桁を弄る(0\dots N-1を3進数と見て展開した)ことでN通りの文字列を作ることにした。無事N通りの文字列が作れたら、それらの先頭に2000...を足し、012を適当に巡回置換することでもう2N通りも得られる。作り方から各桁の文字の分布についての条件が満たされる。

Cも……難しい。先頭の桁から決めていくと、1を置くときは2のべき乗だけ辞書順で大きくなるらしいことがわかる。これはXの対応する桁から1を引けるかどうかで判定可能。0を置くかどうかを判定するため、Xをデクリメントする必要がある。デクリメントは106回くらい行われる可能性があるが、そう何度も上のほうの桁まで見に来ることはないと考えられるため、愚直にやっても間に合う。これに関連して、maspyさんの「next_permutationを105回呼んでも問題ない」というツイートが興味深かった。

Dは、まず1\le i\lt j\le N1\le i,j\le Nに緩めてもよい。最終的に出てきた答えを2で割れば正しい値が求まるからだ。そうして、各(A_i,B_i)のペアについて、相方となる(A_j,B_j)がどんな値であればどこの桁で大小関係が定まるのか、を全探索する。大小関係が決まる桁より前はA_i\oplus B_iA_j\oplus B_jが一致するので、これをキーに使えばペアの情報はかなりまとめられる。まとめた値をvectorなどに溜めておく。次に、逆に(A_j,B_j)を全探索して、先ほどまとめた値とXORを取った和を計算する。これは事前に桁ごとに立っているbitを数えておけば計算できる。計算量がk=18としてO(k^2 N)で、2secくらいかかったが、問題なく通った。

Eも難しかったが、何とか解けた。連続するpopを、その前のpushと組み合わせて見る。もしpushがpop以下であるようなら、どんどん前に遡っていって、必ずpop>pushであるようにしておく(後で見るように、これは不可能な場合があった)。こうすると、popが組になっているpushより前の値を壊してしまうことがなくなる。ある特定の集合を作れるかどうかは、小さいほうから順に「集合に入っている→push」、「入っていない→pop」に対応付けてみて、pushと直後のpopの大小関係が壊れていないことを確認すればよくなる。popと次のpushの大小関係は問題ではないため、そこに自由度がある。ここで、「現在の集合に入っている要素より大きな値をpopしたのが何回か」をキーにして、そのpopの間に埋め込むようにpushするdpが考えられる。

実装したらサンプルが合ったが、残念ながら計算量がO(N^3)になってしまった。しかもdp遷移にcombinationが出て、高速化できそうもない。そこで、先ほどまとめたpushを分解することにした。最初はpopも分解しようとしたが、以前の値を壊してしまわないようにまとめるのが本質だったようで、全然答えが合わなかった。pushだけバラバラにしてみると、先ほどのcombinationはpushに対応するものだったから、1個ずつ考えているということで消え、後にはただ範囲加算のみが残った。これは容易にO(N^2)に落とすことができる。

提出したらWAとREが出た。焦りながらコードを確認した感じ、popをまとめている部分しかREが出そうな箇所がない。努めて冷静に考えると、一番最初まで遡ってもpop=pushとなってしまう場合を見落としていることに気づいた。うまいことemptyのチェックを挟んで書き直し、サンプルを試さずに投げたらAC。コンテスト終了3分前だった。

直後にCodeChef。今日はLunchtimeという種類のコンテストの9月号らしい。初参加なのでdiv.3。当然のように優勝した。レートは初期値1500→1766(+266)。

https://www.codechef.com/LTIME100C

VDATESはよい。TWODISHは全探索。UNQEQはNが4の倍数でないと総和が2で割れず、逆に4の倍数なら構築できる。(1,4)(2,3)のように組み分けするのを繰り返して2つの数列の総和を等しくできる。この時、prefixの総和の差を広げるような要素を優先的に配置すれば、途中で差が0になることはない。SOD3は自明。

ここからはdiv.1と問題が共通らしい。ALBOFACEは、最初にメモ化再帰を書いたらTLEしたので、grundy数を考えることにした。手計算で小さい値を調べていたところ、遷移の自由度がほとんどないことに気づき、計算方法も思いついた。2進表記にして、連続する0をまとめて考えると、上位桁から順にgrundy数を考えていける(冷静になるとgrundy数ではなく真偽値でよい)。INTREPはしばらく詰まっていたが、2\mid Nならば(2N,N)が答えになることに気づいて解けた。2\not\mid Nであった場合は、奇素数pであってp\not\mid Nなる最小のものを探し、(pN,(p-1)N)が答えになる。p-12pより小さい奇素数の積なので、\frac{p-1}2\mid Nが従う。またそのようなpp\lt 100に必ず存在するので、出力の制約も満たせる。

以上6問がdiv.3の問題だったが、それ以降の問題も解けはするようなので、解いていた。SUBLCSは選択したペアの位置も含めた一致を答えるのだと思って何度もWAを重ねた。単純に各値が連続して何度出現できるかを見ればよい。RARRAYは尺取りをする。後ろから前に戻ってくる感じに実装して、前に1つ進めたとき新たに考慮する要素が順序を壊すようなら、考慮しないようにもう一方の端を前に進めてくる。順序を壊す判定はセグメント木で、値→インデックスとインデックス→値を両方区間minで持つ。謎の勘違いを繰り返し、これもたくさんWAを出した。最初のコードはACしてから見ると何を考えていたのかと呆れざるを得ない。MXMNSSUMは答えが負になる場合の処理ができず解けなかった。bitsetでできるなあと思っていたら、立っているbitが区間になるらしい。

div.3の全完には1時間かからなかったが、結局そこから2時間みっちり問題を考えていた。今日最後のコンテストまで1時間あったので、その間に日記を書いていた。午前2時からFHC R2に出た。

Facebook Hacker Cup - 2021 - Round 2

ABcCを通して59位。R3進出、Tシャツ獲得に加え、上位200人なのでTシャツが何か特別仕様になるはずR3の上位200人に対する褒章らしい。ぬか喜び……。

Aは難しそうな見た目をしているが貪欲でいい。マッチングにあぶれた人たちは着替える必要があるが、その時まだ着替えたことがない人を優先的に使う。そうしない場合に比べて損をしない、という事実が初回から順番に成り立っていく。Bは各辺ごとに同じ周波数の2頂点を分割しているかをチェックする。部分木の周波数をカウントして全体の個数と比較することにすると、マージテクで全ての頂点に対して計算できる。スタックオーバーフローが怖かった(どう考えても再帰dfsしたら落ちる制約だった)ので、最初にBFSしてその逆順にループを回し、再帰関数を使わずに計算した。

cは、1つの車を消す操作は最後にまとめて行ってよいこと、上と下にずらすのは片方しか行わなくてよいことがわかるので、あとはずらす幅を全探索。基本的に、ずらしすぎて開けたい列まで埋まってしまった場合を検出すればよいが、ちょうど開けたい列に車をずらしてしまった場合もケアする必要がある。

Cはこれの1点更新。簡単のため、上にずらす場合だけ考えて、下にずらす場合は盤面を反転させて対応することにした。ある場所に車が増えると、「ずらしすぎて開けたい列まで埋まる」場合のずらし幅が少なくなる。列の車の場所をsetで管理しておくと、今のずらし幅に対応する車が必ず存在して、その1個上の車になる。ということで、対応する区間に1加算すればよい。車が減る場合も同様。ずらしたときにちょうど車が来てしまう場合の1点更新も含め、遅延セグメント木で処理できる。解法を思いついてからしばらくはやりたくないと駄々をこねていたが、実際書いてみるとなかなかシンプルになった。それでも2000Bを超えているが。

今日は3h+2h+3h+3hで合計11時間コンテストに出ていた。立派な競プロ戦士になれた気がする。日記を書き上げて午前6時半就寝。

09/26(日)

昨日と同じく午後0時半起床。さすがに疲れがひどいが、昨日の経験から布団の上で眠気で戦っていると食事できなくなることがわかっていたので無理やり身を起こす。カロリーメイトと冷蔵庫にあったフルーツを手早く用意したが、フルーツだけ食べたらコンテストの時間になってしまった。

午後1時からACPC2021 day3。今日はABDCEFGの7完8位。難易度順らしかったが、それよりはsolvedを見て解いた。結果F問題までは爆速で6完最速だったが、G問題で勘違いを繰り返してしまい爆発した。

https://onlinejudge.u-aizu.ac.jp/services/room.html#ACPC2021Day3

Aはどうにでもなりそうだが、ちょっと怖いので丁寧にやった。Bは素因数を数えて2で割る。Dは頂点を追加しながら期待値を求めればよい。CはBをブロックに分けてAと対応付け、そのブロックの作り方を考える。1より大きな要素がブロックに2個以上存在するなら0通り、1個存在するなら左右の順番でcombination、0個なら真ん中をループで決めて1個の場合を足し合わせる。特に3番目の場合分けはちゃんとやると2のべき乗になるらしい。ブロックごとの操作列を組み合わせる時もcombinationを考える必要があることを見落として1WA。

Eは昨日のFHC R2D(の解法ツイート)で見たばっかりで、先頭24個を取り出して全探索すると鳩ノ巣原理から必ず見つかる。Fは怪しげな操作をしているので適当に累積和を取ったらswapになった。つまり累積和の転倒数。一瞬で解けて有頂天になりながら出したら、末尾の要素を変更できないことを見落として1WA。

Gは難しかった。サイクル基底かと思ったがそんなことはない(一般に頂点属性でサイクル基底はやりにくそうだ)。もっと自由な操作ができる。具体的には、いったんGまでたどり着いてから「任意の頂点uに行く→戻ってくる」を繰り返すことで、c_G\oplus c_uをコストにXORすることができる。これを2回セットにすると、任意の頂点2つを選んでXORすることに言い換えられるから、適当にc_0をほかのc_uにXORした状態で基底を計算し、SからGへの適当なパスのコストにXORして最大を求めればよい。パスを求めるのはdfs木とLCAを使ってやった。

……WA。手元で作っていたグラフを眺めていると、SGパスに含まれる辺の本数の偶奇を任意に定めることができた場合はさらにやりたい放題できることに気づいた。上で頂点2つをセットにする必要がなく、最大値を達成するような頂点たちが決まったら、それに沿うようにパスの本数の偶奇を定めればよい。二部グラフ判定を書き加えるとようやくACできた。結局5WA出してしまった。

さて、これでACPC2021の全日程が終了した。今年はオンライン開催で、僕は3日間ともソロ参加かつ、3日間ともボス問題だけが倒せなかった。大学の合宿のボス問題を自分が解けるビジョンが見えないが、昨年の日記(この日記は1年以上続いているので去年の同時期のことが読める!)を読み返した感じ、椅子を温めていない時間は長くなっていそう。

ちょっと食事をした後、午後5時からOpenCupに出た。チームで5完。

最初30分くらいdiv.2の問題ページを見ているというハプニングがあったが、幸い気づくまでに自分が読んだ問題(A-C)はどれもdiv.1と共通の問題だったので、助かった。div.2の順位表を見て、Aは解けなそうと思っていたのに、div.1の順位表ではバカスカ通されていてたまげた。まごまごしているうちにチームメイトが瞬殺したので、実装もしてもらった。連続する正の数を3つ以上足すと素数にはならない、というのは超最近のyukicoderで見たばっかりなのに1ミリも頭に思い浮かばなかった。疲れている?

No.1657 Sum is Prime (Easy Version) - yukicoder

そのあと、B問題を念入りに詰めて、solvedが1桁のころに通すことに成功した。ギャグではない問題を通したのは初めてかもしれない。自分が行動できる回数は高々\sqrt{H_0}種類くらいしかないので、全探索する。そのあとは丹念に場合分け。2次関数の(整数としての)最大値を何回も求める必要が出てきて、ああ……終わった……と感じたが、試しに平方完成して睨みつけてみると、それらによって得られる値が答えに全く影響しないということが分かった。実数範囲に制限を緩めて考えると、たくさんの最大値「の」最大値が直ちにわかって、ほかのケースで考えている値と本質的に一致あるいは小さくなるためOKという感じ。サンプルが合わなくてドキッとしたが、ちょっとした範囲のミスで、エイヤと直して投げたら1発で通った。

E問題が飛んできたので考えてみる。チームメイトの残した考察があまりピンと来ていなかったが、ACした後に見ると大体同じことをやっていたように思える。連続する同じ扱いの値を纏めると考えやすくなって、下から貪欲……と思ったらWAを出した。合計3回くらいWAを出していたら、さっきまでE問題を考えていたチームメイトがコードを読んでくれたらしく、Hackケースを教えてもらった。それで何を抜かしていたのかに気づき、AC。助かった……。

他の人がいろいろ実装している間にJ問題を考えていたら、それなりによさそうな性質を見つけた。パソコンも空いたので実装するか、と思ったが、入力を受け取ったあたりで思ったより実装がヤバいことに気づく。このとき午後8時半を回っていて、ABCまでそんなに時間がなかったのもあり、焦って考えが全然まとまらない。結局ABCまで残り10分くらいになったところで逃亡してしまった。

AtCoder Beginner Contest 220 - AtCoder

7完97位。Fまではそれなりにいい調子だったのに、Gで8WAして何もかもが台無しになった。

Aは\left\lfloor\frac B C\right\rfloor Cで解いた。dc。Bを開いたらあまりにもdc向けの問題すぎてたまげた。自明な5Bコードを書いて提出し、順位表を見に行ったところ、dcを書ける人がすでに通していたため、絶望。CからはC++。適当に和で割って残りをO(N)……と思ったらWA。問題文の不等号が等号なしだった。Dはdp。Eは上って降りる幅を全探索し、それぞれを気合いで計算した。サンプル1が合わなくて大変だったが、一度合ったらそのままACできた。Fは全方位木dp。

Gは、まず線分を全探索して傾きでグループ分け。この時点で答えを求めてしまい、サンプル1が合わないのを見て、等脚台形という条件をすっかり忘れていることに気づいた。等脚台形にするためには、2つの線分の中点を結ぶ線分が元の線分に直交する必要がある。ということで、傾きでグループ分けした中で中点(を適当に移動させて正規化したもの)でさらにグループ分け。重なる線分を選ぶとまずいので、中点も一緒に持っておいて判定する。最後に各グループに対して答えを求める。……WA。かなり面倒なコードを書いたので、解法ミスではなくどこかにバグがあるのだろうと思って探す。数か所ミスを見つけたものの、それらを直して提出したつもりなのに、最初の8WAから一歩も先に進めない。残り20分を切ったころ、大きいほうから2要素を持つ変数の初期値が-2\times 10^9だとマズいことに気づいた。これだと、10^9が2個あったとき、組になって答えが0で更新されてしまう。これを-2\times 10^9-1に直したら通った。重みは2つまとめるところまではint型に収まるな、と思ってわざわざint型を使ったのが裏目に出たらしい。適当に-10^{18}とかにしておけばよかったものを……。

コードゴルフ。Aはコンテスト中のdcコードが最短。Bも5Bコードで、こちらは案の定提出時間で負けていた。CはRubyで書いてからdcで縮めたが、僕がdc 50Bを作って出したころには44Bが提出されており、完敗。しばらく睨んでも縮みそうにはなかった。DはRubyで書いて負け、Perlで縮めたがそちらでも負けた。以上前半4問のうち1問しか最短を保持できていない。最近コードゴルフが盛んで負けまくり。

Hを通した。半分全列挙で、2つの集合STの間をどうするかが問題。コンテスト中は時間がなくて全然考えられなかったが、じっくり取り組んでみると、Sで「選ばなかった頂点」の組から、Tの「選ぶと監視されている辺の本数の偶奇が変わる頂点集合」が求まることがわかる。今度はTの選び方を全列挙して、先ほど求めた頂点集合との共通部分の要素数を見たい。これは、現在監視されている辺の本数の偶奇に対してSから作ったTの頂点集合とTの選び方をそれぞれカウントしておき、2×2通りAND畳み込みをすることで計算できる。

H問題で面白いコードがあった。1900msくらいかかっているので想定TLE解法だろう。まずすべての頂点を選んだ状態から初めて、ある頂点を監視するのをやめたとき、隣接するより頂点番号が大きな頂点それぞれに対してフラグの状態を変える。これは隣接行列の行をXORすることで計算できる。逆に、フラグが立っている頂点を監視するのをやめたとき、「隣接するより頂点番号が小さな頂点のうち、奇数個がすでに監視されていない」ことがわかるので、それらとの間にある辺は監視されなくなり、監視されている辺の本数の偶奇が変化する。今見ている頂点、現在監視されている辺の本数の偶奇、各頂点のフラグの3つでdpを行う。3次元目の値はmapで扱う。

atcoder.jp

この解法でコードゴルフするとかなり短くなった。mapを使うのに#import<map>とすると、入出力のライブラリが使えないので困る。そこで#import<regex>とすると、2B増える代わりにC言語由来の入出力関数が使えるようになる。mapを使う場合はこれかbits/stdc++.hしかないと思っている。

ラノベを1冊読んだ。「精霊幻想記」20巻。最近やっていた話が一段落する巻だと思っていたら、ラストに衝撃的な展開があり、まだ心の整理がついていない。またそれに向けての加速だったのか、最後のほうは展開が目まぐるしくて狐につままれたような気分だ。主人公・リオはこれからどうなってしまうのか……。次巻を怖がりつつも楽しみにしている。

週記(2021/09/13-2021/09/19)

09/13(月)

週記を投稿してから布団に入り、しばらくハーメルンを読み返して寝た。午前9時前だった。先週金曜日の1on1でこの先しばらくやることを確認したと書いたが、結局それから1ミリも進められなかった。

午後3時に起床。15時と午後5時を見間違えたこと、寝ている間に月曜日のミーティングの時間が1時間早まっていたことが合わさって、ついに寝坊してしまったかと冷や汗をかいて飛び起きた。セーフ。

せっかく起きたのでミーティングまでしばらくインターンの業務を進めた。それっぽいコードは書けたが、途中でエラーが出る。サンプルコードをほとんど写したようなものだったが、やはり自分で実行していないコードということで何か勘違いがあるらしい。自分で解決できないこともなさそうだが、設計まで含めて1on1で聞くのが早いだろう。

ミーティングは特に何事もなく終了。今週から自分もスライドを用意して、先週何をやったかと今週何をする予定かをきちんと発表した。来週月曜日は国民の休日らしく、ミーティングが別の日にずれるらしい。そういうこともしっかり考えてるんだなあという気持ちになったが、逆にしっかり考えないと会社としてはまずいのか。

学食に行って帰宅。土曜日に注文したモニターアームが届いていた。思ったより重くて、机の耐荷重が大丈夫か……?という気持ちになる。ダイニングテーブルは奥行きもあって広いが、一方でパソコンデスクほど耐荷重が重くないのが難点であると気づいた。

しばらくハーメルンを読んだりコードゴルフをしたりした後、CF ECR18を埋めようとした。Fはまだ解けていない。

Dashboard - Educational Codeforces Round 18 - Codeforces

Aはよい。Bは難読。特に問題文中の例はゲームの途中から書かれているため、理解するのに苦労した。わかってしまえばシミュレートするだけ、実装は何とでもなる。CはABC182-Cの強化版で、数字に0が含まれること、桁数が105オーダーであること、復元が求められていることから非常に難しく感じた。ABCの方と同じく場合分けをして解こうとしたが、ふとただの桁dpで解けることに気づいた。Dはbitを見て適当にやる。

C - To 3

Eは難しい。各集合の大きさをnn+1であると定めると、必要な条件は\exists q\;s.t.\;qn\le a_i\le q(n+1)と書ける。ここで\left\lfloor\frac{a_i}{q}\right\rfloorはそんなに種類がないので、適当にiを選んで\left\lfloor\frac{a_i}{q}\right\rfloor\left\lfloor\frac{a_i}{q}\right\rfloor-1を全部調べればよい。各na_iに対して最適な分け方は上の条件から出る。

インターン先から届いたパソコンのセットアップを済ませることにした。起動してみるとWindows単体が入っていたので、Ubuntuとのデュアルブートにする。頑張ってマザボの例のアレ(ファームウェアインターフェイス)を起動すると、BIOSではなくUEFIだった。マウスによる直感的な操作でいろいろ調べてみると、HDDのところにUbuntuと書いてある。しかしWindowsのほうから確認したら全ての領域にアクセスできていそうなので、すでにデュアルブートになっていたとかいうことはないだろう。聞くところによると、このパソコンは以前Ubuntuとのデュアルブートだったのを、僕に貸与するにあたってわざわざほぼ工場出荷時の状態に戻してくださったそうだから、その時残ってしまった名残なのかもしれない。以前別のパソコンで使った、Ubuntu 20.04インストール用のUSBを差し込み、起動の優先順位を変更していざインストール。

画面上部に1行だけ映っているメッセージで検索すると、どうやらグラボが入ったPCにUbuntuをインストールするときにドライバがないため起こる現象らしい。確かにオンボードでないGPUが入ったパソコンにUbuntuを入れるのは初めてだ。しかし解決方法が設定ファイル編集によるものらしく、なんだか怖かったのでとりあえず無理やり電源を落として再起動してみると、「Ubuntu (safe graphics)」といういかにもそれっぽい起動オプションが増えていた。それを選んだらちゃんとインストール画面まで進めて感動。デュアルブートを選択して、パーティションも特に弄らずインストール開始。

失敗したというメッセージが出た。Ubuntuにバグレポートを送信すると、既知の問題だった。ブラウザでそのバグのページが開いたので読んだところ、インストールのオプションで「サードパーティー製ソフトウェアをインストールする」にチェックしていると起きるらしい。GPUのドライバはどうするんかいな、と思いながらチェックを外して再度試みると、今度はどうやらうまくいったようだった。

ソフトウェアとアップデートから適当にGPUのドライバを入れる。これにも失敗したという表示が出たが、終わってみるとなんだかいい感じになっているようなので、放置。最後に、Pythonの開発環境を整えて、GPUで計算できるようにする。わざわざUbuntuを入れたのは主にはこのためで、WSLからGPUを使うにはWindows Insider PreviewからWindowsのバージョンを更新しなければならなかったりして、かなり敷居が高い。やってみたらUbuntuを入れるのも敷居が高かったのだが……。

Pythonの開発環境を整えること自体はよくある話なので、適当にQiitaから記事を拾ってきてその通りに進めた。途中でAnacondaを使い始めたので、pip派の自分はそこで分かれる。Ubuntu 20.04はデフォルトで入っているPythonのバージョンが3.8と別に古くもないため、その辺りはデフォルトのままでいい気がしている。特に苦労することなくtorch.cuda.is_available()Trueを返すようになった。

せっかくパソコンをセットアップしたので、これまでWindowsで動かしていたPythonスクリプトを一通りUbuntuでも動かしてみることにした。すると出力が一致しない。なんとなく理由の予想はつくので、また1on1で聞いてみることにしよう。ところで、机の上にキーボードが2台あって、片方でUbuntuを操作してもう片方でWindowsを操作している。かなり誤爆しやすいことが分かったので、十分気を付けなければならない。

これで今日の作業は終わり。シャワーを浴びて布団に入り、本を1冊読んだ。「かくりよの宿飯」7巻。6巻を読んでからハーメルンにハマってしまってちょっと時間が空いた。しかしやはり面白い。僕が好んで読むネット小説とはまた違うタイプの面白さで、たまにはこういうものにどっぷり浸かるのもよい。巻数的に、いよいよクライマックスにつながる流れの中にあるようだ。大旦那様が姿を消してしまい微妙に張り合いがないが、再会を楽しみに読んでいきたい。

午前7時半就寝。

09/14(火)

午前11時くらいにふと起きたところ、ちょうどモニターが届いた。しかしあまりに眠いので放置してまた就寝。次に起きたのは午後3時だった。日本橋ハーフマラソン(増刊号でないほう)で学生15位入賞していたらしく、アマギフを5000円もらった。

今日は丸一日使ってパソコン回りを整えなおす。まず手始めに机の周りのものをすべて取り外し、掃除をした。土曜日に買ったエアダスターが大活躍したが、逆に酷使しすぎて気化熱・断熱膨張によって缶の温度が下がり、結露どころか雫が凍り付いていてびっくりした。

ルーターも取り外していたのだが、実は今日は午後5時半から1on1が予定されていた。直前になって全然準備できていないことに気づき、とりあえずネット回線だけ元に戻してノーパソから参加した。コード類は一応GitHubに上げてあったので何とかなったが、画面共有の時に1画面しかないと、脇で見せる資料を準備するみたいなことができないため、非常に不便だった。使うモニターの枚数は、ひとたび増やすともう減らせなくなってしまうことは有名。

1on1では昨日のコードの動かない点を聞いて解決することができた。また、WindowsUbuntuで出力が食い違う理由もかなりそれっぽいので、一度対処法を試してみることになった。予想がついていたのなら先に試しておくべきだったかもしれないが、今日はパソコン回りを整える日にしていたので、1on1までにそのような時間はなかった。

1on1が終わって、また掃除に戻る。とりあえず一段落して、今度は機器を戻したり取り付けたりする。モニターアームの取り付けは机の後ろに回ることができないとなかなか厳しいものがあるため、机をずらし、まずそれを組み立てて取り付けた。地震が怖いのでネジを閉めるときはできるだけギュウギュウにすることを心掛けた。一か所プラスドライバーを自分で用意しなければならないネジがあったが、1年生の春に家具の組み立てで使ったものが残っていて助かった。

モニターアームを机に立て、モニターの高さを調節しつつ取り付ける。2台あるので、高さや角度を揃えようとしたのだが、ネジを緩めたり閉めたりして高さ・左右の角度を調節するタイプのものだったのでなかなか苦労した。最終的にはちゃんといい感じにできたので、机を壁に寄せ、あとは机に置くモニターを設置し、ケーブル類を全部パソコンに接続して完了。コンセント2口それぞれに6口ある延長ケーブルを差しているのだが、モニター5枚・パソコン2台・プリンター・ルーター・謎の機械(PLCアダプター?)・デスクライト・USBハブでちょうど全部埋まってしまった。そのほか様々なケーブル類は一切まとめていないため、机の下はすごいことになっている。

机の上はこんな感じ。

非常に良い。前々から、モニターを縦に積んで上の画面を微妙に下に向ける配置、その角度にあこがれていた。視界を覆うようなモニターたちよ!これぞロマン!何に使うかは考える必要がない、何故なら、モニターはあればあるほど良いため。

しばらく実際に使いつつ、インターンのコードを書いていた。まず、画面が遠くてよく見えないため、Ubuntuの設定で大きな文字を使うようにした。またターミナルではフォントサイズもちょっと大きくしてある。椅子の配置の問題かも知れないが、右上のモニターを見上げるのが一番首に負担がかかると分かった。そこだけ、明確に顔を動かさないと見ることができない。そもそも横にモニターを並べると結構首を動かすことになって辛い、という体験談も聞いたが、僕の机はかなり奥行きがあるので、今まで免れていたのだろう。

昨日発見した、WindowsUbuntuでプログラムの出力が違う原因を探っていた。実行にそれなりに待ち時間が発生していたので合間合間に本を読みつつ、USBメモリでデータを移してdiffを取る作業を繰り返す。結局昨日予想していた原因はほとんど関係なかった。ライブラリのバージョン違いでもちょっと変わっていたが、最終的に決め手になったのはリストの順番で、とりあえずソートしたら見事に一致した。しかしなぜそれが結果に影響するのかがわからないままである。むしろ影響してはいけない箇所のはずなのに……。

本を1冊読了。「かくりよの宿飯」8巻。大旦那様と再会するまでは剣呑な空気が続くのかと思っていたが、あにはからんや、この巻もそれなりにまったりしていて、安心して読めた。ついに次巻で再会できそうだが、ストーリーが終わるのは10巻なので、まだひと悶着あるのかと戦々恐々としている。

上の段のモニターがスリープで黒くなると、結構視界に入って圧がすごいことを実感した。とはいえ、基本的にパソコンをつけっぱなしで寝る人間なため、スリープを完全に切ると部屋が明るくて困る。

シャワーを浴びて大学生協ラノベの新刊を注文し、日記を書いて布団に移動。

ハーメルンの捜索掲示板をまた漁りまくる。ちょっとでも気になった作品はスマホChromeのタブに開き、保存している。パソコンのタブはシャットダウンすると復帰する手間がかかるが、スマホだとアプリを落とそうが再起動しようがタブを保存してくれるのでかなり便利。少し前まではかなり神経質にタブを閉じていて、ほぼ常に無の状態だったので、スマホのブラウザでタブを開きまくっている人のことを理解できなかったが、今は読もうとしている作品・読んでいる作品で100個近いタブが開かれている。人は変わるものだ。

1作、最近連載が始まったばかりで毎日更新の良さそうなものを見つけたため、最新話まで追いついておいた。

https://ncode.syosetu.com/n4583he/

逆行転生悪役令嬢もので、財閥を動かす話ということで、かなり「現代社会で乙女ゲームの悪役令嬢をするのはちょっと大変」に似ている。「現代社会で~」は僕のかなりお気に入りの作品であるから、当然こちらもかなりツボに入った。1話目のあとがきによれば作者は架空史ものを書いてきた人で、なろうで人気の架空史が逆行転生知識チートものばかりであることに対するちょっとした皮肉としていろいろ設定を作ったらしいが、それはそれとして純粋に面白い。

さらに以前読んだなろうを読み返したりした後、午前11時に就寝。

09/15(水)

午後5時起床。ちょっとコードゴルフをした後学食に行き、その足で原付を買った店に行って保険の更新をしてきた。

年齢が上がっただけで保険料が1万円くらい安くなってたまげた。それでもまだ25000円くらいしている。これまで1年に100kmも乗らない原付に対してそれ以上の額の保険をかけてきたのかと思うと、かなりもったいないと感じてしまう。もちろん、たまたま自分が事故を起こさなかったからそう思えているというだけではあるが。

電車に乗ってまた駅前の電気屋に行く。5枚あるうち右上のモニターは見上げにくく、さらにサブマシンに2枚あっても使いどころが少ないことが分かったので、これまでバックグラウンドで垂れ流していた作業用BGMの動画でも表示させておこうかと思うが、そのためにはパソコンから音声を出力できる必要があった。ということで、スピーカーを買う。ついでにUSBケーブルを購入してHHKBを有線でつなぐことにした。bluetoothだとかなり不安定でよく変な挙動をするし、数分操作しないだけで電源が落ち、復帰のために数秒電源ボタンを押さなければならないのもつらい。

どちらも1000円ちょっと。ついでにオンラインゼミのための板タブレットでも買おうかと思ったが、ネットで調べていたより値が張ったので今日は見送る。会計のときにポイントカードを出したら、先週使った金額の10%にあたる1000円弱のポイントが使用できて、かなり安く済んだ。ポイントカードの威力を思い知らされた形だ。

そのあとはゲーセンで深夜まで遊んでいた。最初の数クレは駅前のゲーセンで手元を撮影していた。

スマホアーム付きの台に待ちができたので移動して新曲のAJ埋めをした。前回ゲーセンに行ったときから狙っていたParad'oxのAJを出せて満足。

最後のほうはHAELEQUINを詰めていたが、どうにも敷地帯ができない。1度など敷地帯以外ほぼAJだったのに、緊張で運指が吹っ飛んでしまった。ノーツが2000ノーツしかなく、赤を100個以上出すので、鳥許容はアタック7個と最近の13+に比べたらかなり少なく、適当にやっていては出ない。でもまあ、今日プレイした感じでは、敷地帯の運指をちゃんと組むことがSSSを出すことの(必要かつ)十分な条件だろう。

帰りにそばかラーメンでも食べようと思ったが、どこの店もやっていなかった。ドンキでパンを買って帰宅。

パソコンにスピーカーを接続したら、マウス操作のたびにゴソゴソと音がする。

ネットで調べた感じでは、別の回路のノイズを拾ってしまっているらしい?音量を0にしても相変わらず出ているので、これは別のものを買わないとダメかも……と思っていたが、ふと給電用のUSBだけ違うパソコンに差したら解決した。謎だが、別のスピーカーを買わずに済んでよかった。このスピーカーはモニタースタンドにぴったりのサイズなのも面白い。

しばらくコードゴルフをしていたが、最近あまりに何もやっていないことが気になったので、とりあえずECR埋めを進めた。月曜日のECR18-Fはあんまりピンと来ないので放置して、今日はECR19。

Dashboard - Educational Codeforces Round 19 - Codeforces

Aはよい。Bはdpしたが、貪欲でもできないことはなさそうだった。Cは貪欲。Dはsetを持ってマージテクしつつ木dpだが、全然関係ない場所にある同じ値を検出してもよいことを失念して1WA。Eはk\sqrt n以上か未満かで処理を分け、前者は毎回シミュレート、後者は前計算。Fは2次元dpを考えて遷移をスライド最小値で高速化。

さらにECR20を開き、A-Eを埋めた。

Dashboard - Educational Codeforces Round 20 - Codeforces

Aは面倒そうな場合分けを考えていたが、書くうちに本当にただの貪欲でよいことに気づいてびっくりした。Bはよい。Cはgcdを全探索して、構築は基本1,2,\dots,k全体を定数倍、最後の要素を増やして調節。Dは二分探索。空白とハイフンの扱いは結局のところ一緒なのに問題設定のために別の扱いをされていて非本質的。Eはdp+復元。

Fに詰まったので切り上げて布団に入り、今日もまたハーメルンの捜索掲示板を徘徊する。自分のツボに入った作品の名前で捜索掲示板を全文検索すると、似たような作品を沢山見つけられて生活が破壊されることに気づき、今日はもっぱらそんな感じでやっていた。しかし見つけた作品のタブを大量に開いた後は、前から読み返していたハーメルンの続きを読んでいて、新しい作品には手を出さなかった。

午前11時くらいに寝落ち。

09/16(木)

午後3時から30分おきの目覚ましで意識を取り戻しつつ、最終的に午後4時半に布団を脱出した。

この構文が人気なことは知っていた。一般に広く知れ渡っていると思っていたが、実のところ特別音ゲーマーの間で流行っているらしいと誰かから聞いたのだった。音ゲーの運営がオマージュしたことで、そのことを強く感じた。ネタにするには結構危険な構文じゃないか?と思っていたが、さすがに運営としての自覚はあるらしく、言葉遣いはかなり配慮されていてあまり原型を保っていない。それでも肝は抑えてあって、個人的には評価は高い。

午後5時から1on1。火曜日の夜(水曜日の朝型?)行っていた検証の話をして、これ以上の追加調査はとりあえず必要ないという結論に至った。それ以外に進捗はないため、あとは少しばかり雑談をして終了。会社としてインターン生、より一般にエンジニアが無理なく働ける体制を整えることを重要視しているらしく、僕が生活リズムを崩壊させていても、それでは1on1の時間をずらしましょう……として下さる。以前までの自分であれば、これぞ求めていた働き方だの、やはり生活リズムを整えることは非本質的だのと考えていただろうし、実際そのような思いは今もあるが、自分にとって一概に良いとは言えないことに気づいた。結局生活リズムを崩して進捗を産めなかったとき、その代償を支払うのは自分なのだ。そして、僕は1人では生活リズムを正すことができない……。

しばらくYouTubeを見たりハーメルンを読んだりした後、学食に行って夕食を摂った。帰ってきてからTCB40に参加した。いつものように、日曜日までのコンテストなのでここに問題の感想を書いておく。先に言っておけば、今回は理論値を達成できたものの、最終問題を詰めるのにかなり時間を食ってしまったため、そこの差で優勝はできていなそう。

https://techful-programming.com/user/event/2242

5問目は何でもできそうでちょっとびっくりしたが、結局各要素の出現回数をカウントした。6問目と7問目はほぼ一緒の問題で、両方imos法をやるだけで謎。8問目はN素因数分解する必要があることに提出直前で気づいて助かったが、その分書き直しに時間を取られた。9問目は明らかだが座圧が面倒だった。10問目はまずディーラーの戦略を整理して勝率を式に表し、適当な範囲で和を取る。範囲を定めるのと式中のmaxの値でさらに場合分けするのをこれでもかというくらい念入りに行っていたら20分もかかってしまったが、その甲斐あって1発でACした。確か時間で点数を引かれるのは想定時間の3割以降だったから、この問題は大体24分、結構危なかったらしい。

日付が変わるまで布団に転がってハーメルンを読んでいたが、今日も何もやっていないため、またECRの続きをすることにした。パソコンの前に戻ってきて、ふと思い立って画面キャプチャのテストをしてみたところ、これまで真ん中のメイン画面をキャプチャできていたのが、いつの間にか左端の画面をキャプチャするようになってしまっていた。調べたところ、regeditでモニタの設定をいったん削除し、改めて番号順にモニターを1枚ずつ増やしながら接続→再起動を繰り返すと正しく設定できるらしい。面倒だったが、何とか真ん中の画面をキャプチャするように戻って安心。

ところで、regeditといえば「人類が増えすぎたので減らしてほしいと頼まれました」というなろうを思い出す。4話目のあとがきにこれが元ネタだったと書いてあった。このなろうは100話くらい読んで放置している。

https://ncode.syosetu.com/n0859fa/

ECRを進める。昨日の続き、ECR20-FGから。

Dashboard - Educational Codeforces Round 20 - Codeforces

Fは昨日、square-freeにして包除したい気持ちになっていた。今日改めて考えなおしてみると、包除に関係する各値は個数さえわかればよく、対応する値にいちいち加算していてもそれほど多くはならない。Gはパッと見厳ついが、区間の区切りだけ取り出して列の圧縮を行うと普通の区間set区間minの遅延セグメント木になる。すぐ気づけてニコニコ。前計算に使用したセグメント木にクエリを投げていてサンプルが合わず、実はsegtree beatsをする必要があったかと焦ったが、そんなことはない。

ECR21。Fは諦めた。GはAho-Corasickのfailure関数を使うはずだが、ライブラリを持っていないので、この機会に作ろうかどうしようか迷ってコーディングしていない。

Dashboard - Educational Codeforces Round 21 - Codeforces

ABはよい。Cは貪欲。Dは左右に分けたとき要素を1つだけ移せると言い換えられるので、分ける仕切りをずらしつつ条件を満たせる要素が存在するかsetでチェックした。Eは重さ3の荷物を何個とるか全探索し、重さ2の荷物の個数で三分探索。

しばらくハーメルンを読んでいた。最近は、今年初めに読了した以下の作品を読み返していた。特に、それまで幻想郷では正体を隠していた世界最強の主人公がその正体を顕わにする緋想天編のラストシーンがお気に入りで、その周辺は定期的に読むのだが、ここ最近は幻想入りのあたりから一連の流れをまとめて読み返していた。やはり面白い。最後までたどり着いて満足。

syosetu.org

朝方、ほかの人の先週の日記を読んだ後、溜めていた自分の日記を書いた。それが終わってからまたハーメルンの捜索掲示板をひっくり返す。今日は「現代社会で乙女ゲームの悪役令嬢をするのはちょっと大変」で検索していた。えらい似たタイトルが引っかかるなあと思っていたら、この作品の2次創作だったらしい。短編だったのでサクッと読んだ。シン・ゴジラを見ていないのでよくわからないが、文章などそれなりに原作と似ている感じはして、いいんじゃないだろうか。

syosetu.org

ゴミを出して布団に入り、紙の本を少し読み進めて就寝。午前10時半だった。

09/17(金)

午後8時半起床。今日は外せない用事が何もない日だったので、何も気にせず目いっぱい寝た。

大学院に合格したはいいものの、入学意思確認書を提出できていない。今週はもう終わってしまった。期限は09/22(水)である。火曜日あたり徹夜して直接教務課に出しに行きたい。

午後9時20分からyukicoder 314に出た。

yukicoder contest 314 - yukicoder

Aから難しい。XY平面にプロットすると、ひし形内部の格子点を数える問題になる。なんというかギザギザな分布をしていて面倒。45度回してひし形を長方形にしたらいいのかな……と思ってふと、最初から45度回転させておけばよかったことに気づいた。そちらでも求める格子点がギザギザに分布していることに違いはないが、縦横がちゃんと座標と合っているので、真面目にやれば場合分けできる。Bは何も考えずに積と以前の和を持ってdpした。これは2019年JAG夏合宿day1Gで似たようなことをやったのを覚えていた。が、聞くところによると大体の項が正負で打ち消しあって消えてしまうらしい。いやそんな考察いるか?という気分ではあるが、面白さはわかる。

https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2973

Cは非常に面白かった。コインを加えた時の確率漸化式を求めてみる。Aliceが勝つ確率をpとしたとき、pではなくp-(1-p)=2p-1から遷移してみると、見事に因数分解できて、最終的な形が各コイン独立な値の積になった。ほぼ同じことだが、p-\frac 1 2から遷移する方法もあるらしい。こちらは答えへのたどり着き方が少し違う。Dは適当に全探索。

Eはかっこ列を2次元平面の経路に帰着させるやつを行う。二次元平面を斜めにおいて、左端がスタート、右端がゴールとしたとき、ゴールは右端で上からいくらかの区間になっている。足さなければならないかっこの数は、スタートからゴールまでの経路で一番上下にぶれた幅で決まるので、ある場所より上・下にいかないような経路数を求めたくなる。これは2次元平面を斜めに切って反転させるテクニックで計算できる。ゴールとなる区間が下にはみ出ると面倒そうなので、最初は2M\le Nの場合だけで解いていた。このとき何を思ったかM\leftarrow N-Mとしても答えは変わらないと思い込んでしまい、サンプルが合わずしばらく苦しんでいた。気づいて絶望しそうになったが、2M\le Nの場合の答えを何種類か求めることで「全体」引く「M\leftarrow N-Mとした場合の答え」が計算できたのでOK。

本を読みつつ時間をつぶし、日付が変わったぐらいからSRM813。oo-で33位、レートは2480→2443(-37)。Medが遅すぎた。

TopCoder Statistics - Match Overview

Easyは自明。Medは最初にdp[Sの何番目][区間が始まっていない会社の個数][区間が終わっていない会社の個数]を書いた。状態O(SC^2)で遷移は「区間を始める会社を選ぶ」→「区間を終わらせる会社を選ぶ」でO(C^2)。これでサンプルが合うことを確認した後、どうやって高速化しようかずっと悩んでいた。実は、今遷移を2重ループで書いているが、1重ループを2回書いても全く同じことができるので、もう4乗になっている。気づいたときは自分の頭の悪さに絶望した。しかしSRM Medの600点の難易度感がよくわからない。今回はたまたま解法ガチャに正解しただけか?

残り20分でHardを読む。たぶん大きいほうから全探索で行けるだろうなという気になり、実際パターンが1桁の場合を検証してみたが、そこで2桁の場合の実装に絶望して諦めた。

ことらんさんの「下水を再利用した街を作る!」シリーズ4本目の動画が投稿されていた。1年くらい空いたのだろうか?今回も非常に面白かった。SRMの残り時間はコメあり・なしで2周していた。

www.nicovideo.jp

チャレンジをコンテストの1部だと認識していないため、コーディングフェーズとチャレンジフェーズの間でも平気でTwitterにコンテストの感想を流してしまう。さすがに直接的なことは書かないようにしているが……。今回のEMは落ちようがないだろうと思っていたが、Medが結構落ちて、システス前から9位くらい上がった。それでも元の順位が低すぎてレートには大ダメージ。Medで包除原理をしていた人が多いと聞いたが、そちらの解法はよくわかっていない。

深夜から昼前までかけて本を読んでいた。「かくりよの宿飯」9、10、11巻。10巻がシリーズ完結で、11巻は短編集だった。非常に面白かった。

まず9巻から。同作者の別作品と多少リンクしているという話は何度もあとがきで目にしていたが、この巻を読んでいる最中にやっと、このシリーズの主人公(津場木 葵)と別シリーズのキャラクター(津場木 茜)の苗字が同じであることに気づいた。よく描写を見れば、以前の回想シーンに津場木 茜らしきキャラが登場していた。髪の毛が橙色という超特徴的な容姿をしているのに、なぜピンとこなかったのだろうか……。

またこの巻で、大旦那様の好物が明らかになる。大旦那様が弁当を食べるときに最初に口にするものだと言われて、そういう伏線が……!と思いつつ9巻の弁当シーンを一通りさらってみると、確かにそうなっている。そういえば1巻冒頭にも弁当シーンがあったな、と思ってそちらも確認したが、残念ながらそのときはれんこんのきんぴらで、9巻で明かされた内容とは矛盾していた。まあシリーズ始めから続くような伏線を用意するのは難しいか。

次に10巻。5巻で登場した敵キャラは物語上のラスボスだったようで、この巻まで嫌らしいことを何度もやっていたが、ついに倒された。伏線という明確な形ではないが、これまでのシリーズで培われた各キャラの特性が存分に生かされてクライマックスを盛り上げており、非常に良かった。大旦那様が天神屋に帰るシーンはなんとも感慨深く、涙が出てきた。そんなシーンでも口調を崩さないキャラのせいおかげで、シリアスな場面にも一つまみの笑いがあるのは、シリーズを通しての特徴かもしれない。

勢いで11巻も読み切った。完結して数年後の話。これまで登場したキャラが総出演で、元気な姿を見ることができてうれしい。いろいろ関係性は変わっていたが、みんなあるべき場所に落ち着いたという感じがした。ただ欲を言えば、もうちょっと現世での話も読みたかったか。主人公と大旦那様が現世で一緒に買い物をしているとき、大学の同級生と遭遇して、大旦那様がキャーキャー言われる……というのは非常に僕好みの1シーンだろうが、回想という形でサッと流されてしまった。天神屋の社員旅行で現世に行くという話が、何度も語られているにも関わらず結局この巻に描かれなかったので、また別の外伝が出るのではないだろうかと楽しみにしている。

さて、2週間とちょっとかけて「かくりよの宿飯」シリーズを読み切った。記憶が新しいうちに同作者の「浅草鬼嫁日記」のほうを読み返して、リンクしている箇所を探してみたいと思う。今は本が実家にあるので、そのうち帰省したらやってみよう。

ECR22のA-Dを埋めた。

Dashboard - Educational Codeforces Round 22 - Codeforces

ABはよい。Cは2頂点からそれぞれ最短距離を求めて、相手よりも自分からのほうが近いような頂点にはたどり着けるので、その中で相手から最も遠い頂点を探せばよい。似たようなことはARC078-Dでやった。Dは2つの部分列を作るのに、現在見ている要素が先頭になっていないほうの部分列の先頭を持っておくdp。問題タグにflowと書いてあってびっくりした。

D - Fennec VS. Snuke

布団に入る。くいなちゃんがミステリー小説を書いたらしいので、読んでみた。一口サイズでいい感じ。様々な可能性が丁寧に潰され、確かに不可能犯罪のように思えたが、解決編で明かされたトリックは割とあっさりしていてびっくりした。多分一番のミスリードは、作中の探偵が誤った結論に達していた部分で、問題編最後の描写も含め素人探偵に対する批判的精神があって面白かった。

くいなちゃんミステリー - くいなちゃん小説

さらに少しハーメルンを読み、午前11時に就寝。

09/18(土)

午後7時起床。

起きてtwitterを見たら、今日の昼頃行われたJOI一次予選の問題が2時間前に公開されていてびっくりした。慌てて解いたが、自明な最短はもうすでに取られていた。AとBはdc、CとDはRaku。Bはテストケースハックで、Dは良さげな演算子を見つけてそれぞれ縮めることができた。

JOI 2021/2022 一次予選 (第1回) 過去問 - AtCoder

午後9時からABC219。今日は7完。序盤にペナを重ねてつらい気持ちになったが、FGあたりをそこそこ速く解けていたらしく、順位表の1ページ目にいた。ただ賞金は逃したようだ。

Sciseed Programming Contest 2021(AtCoder Beginner Contest 219) - AtCoder

Aは面倒。とりあえずAWKで出したらFAだった。直後自明な更新ポイントがあったので1B縮めておいたが、現在の最短は言語から違う。BはPerlで解いた。Cはbashで出したらWA。よくわからない仕様を踏んだかと思ってC++で書き直したが、実は文字を置換する順番が違っていた。

Dは適当にdpを書いたらWA。問題文を読み直したときに、たこ焼きとたい焼きが一瞬同じ単語に見えてびっくりした。しばらく考えて、XYを大幅にオーバーするケースも考慮しなければならないことに気づいた。どうやって書けばいいのかすぐにわからなかったが、しばらくしてオーバーした部分は無視してよいことに気づいた。

Eは面倒。堀をdfsやらで探索するクソ面倒な問題かと思ったが、視点を変えて堀の内側に入れるマスの集合を全探索すればよいことに気づいた。意気揚々と実装して、堀の内側のマスの連結性もチェックし、サンプル1を試したところ、1720が出てしまった。validと判定されたマスの集合を全部出力して適当ににらめっこし、内側に穴が開いたケースが怪しいことに気づいた。問題文からはそういうケースがvalidかどうかよくわからなかった(同じ勘違いで1720が出た人が大量にいたらしい)が、とりあえず省いてみる。省くのも結構難しく、いろいろ考えた結果、周囲1マスを増やして堀の外側も連結になっているか調べることにした。これで再度サンプル1を試すとちゃんと正しい答えが出たので一安心。

Fも面倒。1回の文字列で移動する差分と通過するマスを求めたとき、掃除されるマスの集合は、1回の文字列で通過するマスたちに差分を適当に足した形のマスになる。その重なり具合を調べればいいので、差分をうまく足し引きして通過するマスの座標を正規化し、それの一致を見ることで重なりうるマスをまとめ、それぞれについて差分を何回足した場所のマスが掃除されるかを、区間の和を求める感じで計算すればよい。

Gは最近ほとんど同じ問題を見た覚えがあって、怪しみながら次数の平方分割を書いたら何の問題もなく通った。僕はPASTの過去問(PAST5-O)を思い浮かべていたが、それより典型90問の83問目がよっぽど似ていたらしい。確認したらほぼ同じだった。Hは適当に枝刈りしたら案の定TLEして、なんとなく凸包っぽさを感じたあたりで、残り時間が10分もないこともあって諦めてしまった。

083 - Colorful Graph(★6)

コードゴルフ。Aはdc。BはVimで置換するコードを作って実行するのが短いらしく、Rakuで配列のインデックスを使うコードを書いたがVimより1B長かった。Cはコンテスト中に置換の順番の間違いに気づきbashで提出、その後Vimで出したものが最短。Eは僕のC++が現在の最短になっている。

DはOctaveのglpkで解ける。(ところで、cygwinからOctaveを起動するとやたらめったらオーバーヘッドがかかって非常に重いので、Ubuntuにインストールしてこれからはそちらでコーディングすることにした。)さて、glpkで適当に書いて提出したところ、1ケースREしてしまった。ケースが公開されていないのでなぜ落ちているのかわからない。とりあえず入力フォーマットは正しい。しばらくテストケースの特定作業をした結果、N=2で答えが2であるようなケースでREしていることが分かった。そこでいろいろ入力を変えて試していたところ、X=Y=300A_i=B_i=151\;(i=1,2)のケースでglpkがエラーを出すことに気づいた。おそらくglpkのバグだろう。

どうしようもないので、最初はN=2のケースがこれ1つしかないことを利用して、場合分けして直接2を出力するようなコードを書いて通した。その後、入力を増やすことを思いつく。A_{N+1}=B_{N+1}=0という弁当を増やしても答えには影響しない。残念ながらこの通りの弁当だとREは解消されないが、A_{N+1}=-1にしたら通った。

午後11時半からCF #743 div.1。ジャッジが詰まりまくってunratedになった。ABが難しくてWAを出していたので助かった。

Dashboard - Codeforces Round #743 (Div. 1) - Codeforces

AはDAGチェックして最長パスを求める問題。ループ検出に失敗して1WA。最長距離が更新されない頂点があったときにループがあると判定していたが、これは誤りで、ループがあってもその外から最長距離を更新される可能性はある。

Bは難しい。基本的には左から貪欲に消していきたいが、左端が1だった場合が困りもの。この場合はそこから右にずっと見て行き、左端から1が続く連結成分のサイズを偶数にできたら(さらにそれが列全体でなければ)OK。最初から連結成分のサイズが偶数の場合はそれでよいが、そうでない場合は途中適宜操作して0を1にしつつ、うまく別の1の場所まで伸ばして、連結成分を1減らすような操作をする必要がある。コンテスト中は、左端がダメでも右端からできるならOKだということで、左右反転して2回チェックしていたが、実は左からだけでよい。左から上記の操作をして列全体になってしまったなら、右から操作してもそうなる。

Bを解いている最中にunratedが決まり、それからはABCに戻ったりして遊んでいたが、情けない結果を残すのも恥ずかしかったので改めて解いていた。Bを通して一度は満足したものの、しばらくしてCも解けたので実装。残り20分もないなかギリギリで書ききって投げたら9ケース目でREした。配列外参照を見つけて修正し、システス後に投げたら通った。Cは基本的には区間dpで、ただし本質的な場所だけ計算する。本質的な場所とは区間の両端が同じ色で塗られているようなもので、そのような区間は謎の制約から高々20N個しかない。区間の長さでソートして、以前の結果を使いつつ毎回O(N)のdpをする。

ABC219-Hを解説を見て通した。難しいデータ構造やアルゴリズムを使うのかと思ったら全然そんなことはなく、ただただ頭のいい言いかえを繰り返してdpに帰着しており、びっくり。僕も区間dpは少し考えたが、距離とスコアを同時に持てなくて棄却したのだった。その距離を、いろいろな言いかえ・計算の分解を経てO(N)種類の値に収めるのが本質。

朝方ハーメルンを1作読んだ。「創造神が行く幻想の世界」。設定は良さそうだったが文章がカスであまり身が入らなかった。序盤など、もともと台本形式だったものに無理やり地の文を足したらしく、リメイクと称してはいるがただただ読みにくいだけ。オリキャラたちもそれほど好きになれない。ただ、今がちょうど幻想入りしたあたりなので、これからはちょっと面白く感じられる可能性がある。

syosetu.org

布団に入ってしばらくハーメルンを読み、午前11時半に就寝。

09/19(日)

午後4時と4時半の目覚ましでは、意識を取り戻しはしたものの、布団から這い上がれなかった。午後5時ギリギリになってようやくパソコンの前に座った。今日もOpenCup。よくわからないのでリンクは貼らないことにした。

今日はチームで7完。相変わらずチームメイトが強い。明確に得意分野を持っている人という印象で、こんなの無理やろと思っていた問題を通していくのを見てすごいなあと言っている。解法を追っかけているわけではないため自分の身になっていないのがもったいない。僕も2問書いたので先週よりはチームに貢献したと思うが、両方ギャグみたいなものだった。

具体的にはAとHを書いた。Aは真っ先に読んでちょっと考えたが、OpenCupだし激ムズ問題しか出ないだろうと恐れをなして逃げ出した。順位表でかなり通されているのを見て再度考え直し、ギャグの構築であることに気づいた。Hはチームメイトとしばらく考えていたが、まっとうに構築しようとすると頭が壊れたので、適当に生成して埋め込むのをやってみた。案外早く全ケースに対する構築が見つかって、むしろファイル出力だったり、そこから1つのソースコードにまとめなおすほうで少し手間取っていた。僕はサイクルに対角線を張るのを試していたが、maspyさん曰く、ちょっと確率調整したランダムグラフでもすぐ見つかったらしい。

残り時間でGを考えていた。僕は、答えをパターン分けして、それぞれいくらか重複しつつ数え上げたあと、うまく線形和を取ることで答えの値だけ得られないかということを試行錯誤していた。結局それはうまくいかないままコンテストが終了してしまったが、終わる直前にチームメイトが、値を2種類だけ計算することでうまく相殺されるような式を見つけていた。コンテスト後に投げたら通ったらしい。

さて、OpenCupが終わったら直後にARC126だったのだが、その前に、OpenCup中に両親が仙台に来てくれたことに触れておきたい。

結局この夏は富山に帰省しないことにして、代わりに両親が車で仙台まで来てくれた。時間が遅かったので夕食を食べに行くようなことはなかったが、母がラーメンを作ってくれた。自分の部屋のキッチンからまともな料理が出てくることに新鮮な驚きがある。そして、持ってきてくれたお菓子や総菜を部屋に収納し、代わりに既読本だったり大きな段ボールだったりを持って帰ってくれた。滞在時間はかなり短かったが、また近く免許更新のため富山に帰るので、それまでしばしのお別れである。

午後10時からARC126に出た。5完9位。

AtCoder Regular Contest 126 - AtCoder

Cまで通した時点で1位と、序盤はかなりいいペースだった。そういえば先週もOpenCup後にCGR16に出て大成功したのだったか。5時間コンテストの直後はヘナヘナになっていて、別のコンテストに出てもまともに問題を解けないだろうと考えていたが、実はそんなことはないようだ。僕が考えるに、おそらくOpenCupの問題に手も足も出なくて精根尽き果てるほどの考察をしておらず、結果長いコンテストの間にいい感じに眠気が取れ、リラックスし、それでいて頭は競プロモードに入っているのが良い影響を及ぼしているのだろう。あるいはたまたまCGRとARCで得意セットが続いているだけか。

Aは丁寧にやる。考察の流れはこんな感じ:まず長さ3だけ奇数なので2本まとめ、次にすべての棒の長さを2で割る。長さ3の棒とペアにするのは長さ2を1本か長さ1を2本のどちらかで、長さ1を残したほうが後々動きやすくなるため、長さ2と優先的にマッチングする。これで棒が2種類以下になるので、あとは答えまでストレートにたどり着ける。

Bはa_iでソートして実家dpしたい気分になる。a_i=a_jなるijを同時に使わないように、タイブレークb_iの降順にしておけばOK。Cは、答えが\max Aを超えるようならばただの割り算で求まる。そうでない場合は、例えばgが答えとしてありうることはK\ge\sum\left(\left\lceil\frac{A_i}g\right\rceil g-A_i\right)が必要十分だが、この\left\lceil\frac{A_i}g\right\rceil gとしてありうる値が\frac{\max A}{g}種類しかなく、1つ1つ見ながら累積和を使うことで必要な操作回数が求まってチェックがO\left(\frac{\max A}{g}\right)でできるため、1\le g\le\max Aを全探索できる。

Dはちょっとハマった。順列をどれだけ作ったかをキーに持つbitDPをする。見ている要素を順列の外に避けるか、あるいは順列の1部として組み込むか。このうち外に避ける操作の際、作っている順列の左右どちらに避けるかでコストが違うので、両方計算して小さいほうを取らなければならない。ここの処理をよく考えておらず、最初にACしたコードでは左右からそれぞれbitDPして(左から作った順列は左にしか避けない遷移になっている)、最後にマージしていた。マージにO(K)かけたので全体でO(NK2^K)となり、さらに一番内側のループで毎回__builtin_popcountを呼び出していたので、1000msくらいかかっていた。

Eはエスパー。サンプル1の2回目のクエリを考えてみる。数列の全体から5を引いて(0,0,1)であるとしてもよい。これに対し、隣接する2項(a,b)(\frac{a+b}2,\frac{a+b}2)にする、という操作だけ何度か繰り返してみた。すると(\frac 1 4,\frac 1 4,\frac 1 2)が得られ、点数は\frac 3 4点となる。また全体から\frac 1 4を引くと、元の数列を\frac 1 4倍した形になっていることに気づく。つまり、この数列に対するf(n)の極限は\sum \frac 3 4\times\left(\frac 1 4\right)^i=\frac 3 4\times\frac 1{1-\frac 1 4}=1と計算できて、サンプルの値と一致する。

3回目のクエリも考えてみる。今度の数列は(0,1,2)。初手で(0,2)を選んで操作すると1点で終わってしまうことから、どうやら一般にソートしたときに隣接する2項を選ぶのが最適なように感じられる。とりあえず(0,1)で操作すると(\frac 1 2,\frac 1 2,2)\rightarrow(0,0,\frac 3 2)で点数は\frac 1 2点。ここで、先ほど(0,0,1)から1点が得られたので、両方\frac 3 2倍することで(0,0,\frac 3 2)からは\frac 3 2点が得られることがわかる。実際\frac 1 2+\frac 3 2=2となって、こちらもサンプルの値と一致する。

ここでエスパーをする。与えられた数列をソートして、隣接する2項をならす操作だけ考えればいいのではないだろうか?しかもそれは左から順に行われる。いかにもよさそうな見た目をしているので、これで考察を進めることにした。まず、点数を計算するために、(0,0,\dots,0,1)をならすとどれだけ加点されるかを計算することにした。(0,1)=\frac 1 2(0,0,1)=1(0,0,0,1)=\frac 3 2。どうやら数列長に対して線形らしい(ここもエスパーしたが、右端の(0,1)(\frac 1 2,\frac 1 2)と操作することで帰納的に示せるようだ)。

さて、先頭i\;(2\le i\le N)項をならすことを考える。先頭i-1項はならされているので、その値は平均、\frac{\sum_{j=1}^{i-1}A_j}{i-1}。これを先頭i項から引くことを考えると、先ほど点数を計算した数列の定数倍になるので、得点もその定数倍、具体的には平均を引いた後のA_i\frac{i-1}2倍した値になる。まとめると、ソート済み数列に対する答えは\sum_{i=2}^N\frac{i-1}2\times\left(A_i-\frac{\sum_{j=1}^{i-1}A_j}{i-1}\right)となるようだ。

適当に\sumを分解することで、\frac{-N-1}2\sum A_i+\sum A_i\times iを得る。これは1点変更が発生しても差分を考えれば更新できる。ソート済み列に対する挿入・削除を実現すればよくて、挿入は、自分に振られるインデックスを求めて掛けた後、それより後ろにある要素はインデックスが1増えるので、値の総和だけさらに増やす。BITで要素の分布と分布に対する値の和を持つことで計算でき、削除も同様。今回は値が大きいのでクエリ先読み+座圧が必要。実装して、サンプル2はN=2なのであまりあてにならないがとにかく答えが一致することを確かめ、提出。

WAを食らって絶望してしまったが、オーバーフローだった。答えのmodを取らなければならないことに終盤気づいて、出力の部分だけ書き換えたのだが、値を保持する変数もmodintにしておく必要があった。値とインデックスの積の和は最大で\frac{N^2}2\times 10^9\approx 4.5\times 10^{19}くらいになる。

Fに1時間近く残したが、そこから何一つ進まなかった。初手何をすればいいのかすらわからない。メタ的に考えて、(a,b,c)は3次元空間の点だと思えるから、整数じゃなくて実数の領域として極限値を求めるのかなとも思っていたが、それで何か得られたわけでもなかった。

コンテストが終わったあたりでTCB40の順位表が更新され、最終順位が出た。最終問題がかなりてこずる問題だったらしく、単独理論値を出して優勝した。時間的にも10完勢の中で一番速い。最高!TLを見た感じでは8問目のコーナーケース(L=0N=1か?)も凶悪だったようだ。

コードゴルフ。Aは朝方dcで通した。思いのほか短くなった。アルゴリズムを吟味するために、短めのコードをいろいろと読んで、結局僕が使用したのはこの提出と同じもの。

atcoder.jp

BはABC038-Dと全く同じコードで通る。そこからさらに縮んだが、現在の最短を思いついたのが少し遅く、ARCのほうでは最短を取られてしまった。ABCのほうは僕が出したコードが最短になっている。Cは手を付けていなくて、DはCrystal。

D - プレゼント

最近いろんな人がCodechefに出るようになっている。最初出会ったときに謎インドコンだと思って敬遠したっきりなのだが、やっぱり自分が出ていないコンテストがあるとちょっと焦燥感がある。今からでも始めるべきかもしれない。

週記(2021/09/06-2021/09/12)

09/06(月)

先週の週記を投稿した後は、しばらく人の日記を読んだりKaggleでよく使われているモデルについて調べたりしたあと、布団に移動してしばらく本を読み、午前9時半に寝た。

しかし、ここで先週の週記に書けなかった日本橋ハーフマラソン増刊号の初動についても触れておきたい。この問題では過去の動きが将来にかなり大きな影響を与えるようなので、最後まで操作列を作ってから途中を弄るのは難しい、というより不可能だろう。ということでビームサーチを書きたいが、どういう風に書くかよくわかっていないので、とりあえず幅1のビームサーチに絞って書いてみることにした。

盤面の評価値は、これまで稼いだ金額にプラスして、まだ収穫しておらず枯れてもいない各マスの価値を収穫機からそのマスまでのマンハッタン距離で割ったものの和。これで6132813点。その後すぐ、必ず収穫機が連結であるようにして、将来の各マスの価値を生えるまでの時間で割ったものに置きかえ、さらに現在生えている価値に少し重みづけしたら、120452453点になった。連結性が効いたのだろう、実際その後重みづけを変えて、将来の各マスの価値により大きな係数を掛けると、133149923点になった。これまで稼いだ金額との比も重要のようだ。この点数は当時1位だった。

このあたりでビジュアライザに掛けてみると、将来的なマスの価値を重視するあまり序盤の動きがかなり遅いと感じた。そのため、収穫機が1台の間は現在の価値だけで遷移してみたが、逆に点数は下がってしまった。序盤のマスの価値は終盤に比べて十分小さいため、無視してよいのかもしれない。ここまで貪欲法で実装しているが、実行時間が1800msとちょっと心配なので、適当に高速化。200msくらい削って同じく133149923点を出すコードを提出し、この日は切り上げた。

午後3時半起床。しばらくコードゴルフをして、午後4時半からインターン先の週1のミーティングに参加した。先週の成果を報告する場で、僕が今週発表することは想定されていなかったのか特に資料など用意するようには言われていなかったが、せっかくなので1日稼働してやったことを口頭で述べた。ミーティング自体は問題なく終了。その後勉強会の時間があった。今日はパズル系の発表で、ミーティングに参加している人々と共に頭を働かせた。かなり興味深かった。インターン生でも発表してよいらしいので、毎週の様子を見つつ内容を考えておきたい。

インターン先から僕のところにパソコンが送られてくるかも、という話になったが、モニターとキーボード・マウスはこちらで用意する必要がありそう。自分のパソコンからモニターを引っこ抜くのは寂しいので新しいものを買ってもいいかもしれないが、そうすると今使っている机に並べることはできないので、ディスプレイアームが必要になる。僕はパソコンデスクとしてダイニングテーブルを使っていて、これは幅も奥行きもあってかなり広々使えるのだが、ディスプレイアームの設置に対応しているのかだけが心配。一度駅前のヨドバシカメラにでも行って現物を確認する必要があるだろう。

余った時間で、Kaggleに興味がある面々が集まってチームを組もうという話になった。チームを組むということ自体に非常に興味があって、ぜひやってみたかったのだが、残念ながらコンペのチーム人数制限が3人だったので組めなかった。以前は5人だったらしい。

ミーティングが終わってからはすぐ業務に入らず、しばらく本を読んでいた。「かくりよの宿飯」5巻を読了。3巻ラストの衝撃的なシーンから続く一連の流れがこの巻で終わった。単純なので、悪役っぽい感じで登場したキャラがいたら最初は悪感情を抱いてしまうが、その後しばらくかけてそのキャラの性格や信念などに触れると、すぐ好印象で上書きされる。でも敵だったキャラが味方に付くという展開は非常にありがちなので、その点ではよいことなのかもしれない。また新たな敵キャラが登場したが、今のところはとりあえずやり込めることができており、1巻で提示されたストーリー上の謎も1歩前に進み、総じて非常に満足のいく終わり方だった。

午後8時半くらいから業務を開始して、午前1時半くらいまでずっとコーディングしていた。とりあえずコード読みの一環としてリファクタリングをしており、自分が思うきれいなコードを書こうと邁進していたが、今書いているコードは保守性が求められるものではないため、実は必要ではなかったのかもしれないという思いがぬぐえない。可読性については元からあまり変化がない、というのも、自分が思うきれいさとは、例えば型ヒントをつけてmypyでエラーが出ないことだったり、関数を切り分けたり統合したりすることであって、コメントをつけるという作業はほとんど行わなかったからである。残り1ファイルになって、少し手を入れたくらいで今日は切り上げた。

エクセルファイルをPythonから読み込むことが多いが、この作業は結構重い。僕が読んでいるコードを以前に書いた人も、その点は重々承知しており、エクセルファイルを読み込む関数をいくつか用意して用途によって使い分けていたが、なおかなりの処理時間を使っていた。ある特定のシートしか必要ではない状況にあっても全体を読んでしまっているということに着目し、特定のシートだけを読み出すような関数を用意してみたところ、かなり処理速度がアップした。手元で50分以上かかっていた実行が10分程度で完了するようになり、非常に楽しかった。

Kaggleを少し進める。ほんの少しだけ調べた結果、モデルはLightGBMがよく使われているとか、特徴量を考える作業が多いとかを聞いて、試しに適当にそれっぽい値を増やして学習させたら、スコアが結構上がった。集団を追い抜いたようで、順位も400位くらい上がったのではないか。それでもコンペの参加人数が多いためまだ順位表の下であることに違いはないが、結構元気が出てきた。特徴量というのは本当に必要なものを少しだけ用意するのがよいと勝手に思っていたが、実はそういう重要度を考えるのはモデル側がやってくれるので、こちらは関係ありそうな値を手当たり次第に放り込んで観察するのが基本的なやり方らしい。

布団に移動してしばらく本を読み、午前6時就寝。

09/07(火)

午前11時起床。かなりつらかったが、正午からメンターさんとの1on1をお願いしているため、無理やり起きる。完全に自分が悪い。信じられないくらい頭がかゆかったので慌ててシャワーを浴びたが、よく考えると昨日シャワーを浴びていなかった気もする。

正午まではマラソンの続きをしていた。ふと、昨日の評価について連結成分の大きさを考えていないことに気づいた。将来的なスコアに連結成分の大きさを掛け合わせ、重みづけを少しいじってみたところ、168165265点へと大幅に増加。何とか順位表の1ページ目に返り咲いた。

今日の1on1では、とりあえず今やっていることが終わりそうだということを報告。そのあと何をするかについて話した。いよいよ機械学習をやってみるようで、サンプルコードを紹介されて読み、実際に手を動かしてみることになった。

そのあとは業務に関係のない話として、Kaggleの進め方についてまたアドバイスをいただいた。Kaggleは競プロとは違ってコミュニティで知見を共有しスコアを伸ばすのが推奨されているので、いろいろな提出が公開されるらしい。聞いた感じでは、公開された提出に自分なりのアイディアを盛り込むことでスコアを伸ばすのだという認識。また1回の提出で1時間くらいnotebookを動かすのは普通にあることらしく、競プロとは全然違う時間感覚だなあという気持ちになった。昨日、特徴量を手当たり次第に放り込むということを書いたが、そういう「できるだけ様々な要素を考慮する」ことに関連して、Kaggleでは2つのモデルに結構な精度の違いがあったとしても、ある程度悪いモデルも含めて混ぜ合わせたモデルを作る(アンサンブル)のが結構効くようだ。これは自分の直感にかなり反していて興味深かった。

その後大学生協とコンビニに行って買い物をし、食事。そういえば2回目のワクチンを接種してから2週間が経過したため、fully vaccinatedと言ってよいだろう。帰宅して、業務を開始する気にならず(おそらく、今やっていることが終わったら機械学習という未知の領域に踏み出すことになるという恐れから)、しばらく本を読んでいた。

かくりよの宿飯」6巻読了。前の巻でストーリーが一段落したので、この巻は比較的まったりしていた。ところがまたラストになってきな臭くなって、5巻ではやり込めることができた敵キャラがまた姿を現した。一体どうなってしまうのか。またその直前、主人公と鬼神の大旦那の関係にかなりの進展があって、こちらは非常に健康に良かった。

7巻を手に取って読もうとしたが、急激な眠気に襲われ、布団に倒れこんで、午後7時くらいから午前0時半まで寝ていた。

夕方に14の1落ちが出ていたのはツイートを見て知っていたが、手元動画も撮影していたようで、投稿されていた。歴史的資料。

www.youtube.com

結局今日はインターンの業務を一切行っておらず、非常にまずい。まずいが、とりあえず日記を書くことにした。その間マラソンに関していくらか新しいアイディアが生まれたので、それも記しておく。

まず、最初の850ターンは収穫機を買えるなら買うという方針にして、179976413点。次に、将来のマスの価値として「生えるまでの時間」で重みづけしていたのを「枯れるまでの時間」としたところ、202885296点まで伸びた。提出時は21位とギリギリ順位表の2ページ目になっていた。

日記を書き終えてから、1時間だけインターンのコードを書いて、もらったリポジトリのコード読み・リファクタリングが完了した。一応もらった時のコードと出力が変わっていないことは常にチェックしている。これで次から機械学習か、と思ったのだが、その前にコードの出力を眺めていたところ、微妙に怪しい部分があった。明日のミーティングでちょっと聞いてみることにした。

ちょっとコードゴルフをし、ラノベの新刊チェックをして、午前6時前に布団に入った。ネット小説をチェックすると東方遺骸王の更新が来ていたので、読む。前の話から一気に数百年くらい飛んだようで、そういうのはかなり好きな展開である。人間の寿命の短さを感じる。また、かなり昔から出ていた紅美鈴らしきキャラは名前が違っていたが、便利のために改名したという形で、その師匠ポジなどではなく本人そのものだったことが明かされた。かなり膨大なバックグラウンドがついたことになり、感慨深い。誰かの感想に書かれていたが、原作でただの門番をしているけれど、実は(この作品の設定上は)屈指の長命キャラであるというのがかっこいい。

そのあと、流れで捜索掲示板を漁り、1作見つけて読みふけってしまった。20話もいかず完結していたが結構読みごたえがあり、2時間半ほどかけて読了した。

syosetu.org

かなり良い。コナンのストーリーは事件発生から解決までの間がほぼダイジェストになっていて、この作品の元となった部分の原作漫画を前半少ししか読んでいなかった自分はなかなかついていくのが大変だったが、それはそれとして少年探偵団と輝夜の関りが非常に健康に良い。輝夜がその美貌でモデルにスカウトされ、一躍時の人となるという設定も好み。ただそういう表面的なことだけではなく、ちゃんと底に一連の流れがあって、綺麗にまとまっているのも満足感が高い一因である。

明日の1on1は午後3時からの予定だ。生活を完全に破壊してしまい、慌てつつ午前11時前に就寝。

09/08(水)

午後2時、かけていた1度目の目覚ましで意識を取り戻す。二度寝するのはさすがにまずいため、根性で起き上がった。しばらくパソコンの前でボーっとした後、1on1が始まった。

昨日発見した出力の怪しい部分は、この後影響が大きいようだったらまた考えることにしましょう、という話になった。まあそういうものか。個人的には納得のいく処置であるが、その納得の理由を詳しく書くのは控えておこう。その後、火曜日に紹介されたサンプルコードの話になって、まだ読んでいなかったのだが、少し手ほどきを受けた。実はそもそもMNISTやImageNetが何を表すかもわかっていなくて、適宜ググりながら話を聞いた。サンプルコードは多少長くて少し骨が折れそうだと思っていたが、今日の話で出てきた部分が勘所のようなものなのだろうから、そこから周りを見ていけば何とかなりそうな気がしてきた。

また、業務に関係ない話として、自分の生活習慣が崩壊していることを申告した。このままではいつか絶対1on1に寝坊すると思ったからだ。まあもともと先方の予定を聞いて空いているところに入れていたので、もっと夕方にずらすならそれで特に問題ないらしい。そのあたりかなり柔軟に対応してくださるのが非常にありがたい。働きやすさを感じている。

1on1が終わったらまた寝ようと思っていたのだが、思ったより意識がはっきりしている。しばらくパソコンの前でグダグダした後、学食に行くことにした。雨が降る中クロックスで外出。帰ってきたらクロックスの中の汚れが足に移ったのか、足からひどいにおいがしてきて、かなりげんなりした。確か大学1年生の時に用意したものだから、もう4年目、さすがに買い替え時か。

帰宅してまたハーメルンを漁っていた。今やるべきことではないという思いが強いが、久しぶりにネット小説を読む体験というのは止めがたいものがある。結局今日のECRのちょっと前まで読んでいた。

こどふぉを開いたら、自分が2件のコメントで言及されたと通知が来ていた。見に行ってみると、Tシャツが当たっていたことを知った。Deltix Roundというちょっと前のdiv.1で上位100人にギリギリ入っていたので1着、さらにCGR15の31~500位にランダムで配られるので1着。これがこどふぉで獲得する初めての衣類となりそう。

午後11時半からECR113に出た。5完。

Dashboard - Educational Codeforces Round 113 (Rated for Div. 2) - Codeforces

Aはギャグ。Bは勝ちたいプレイヤー同士が順繰りに勝つように埋めればよいが、勝ちたいプレイヤーが1人または2人しかいない場合は不可能。2人の場合を見落として1WA。Cは最大値と2番目の最大値の差が1以下でなければならず、ちょうど1のときだけダメな順列が存在するので、求めて引く。Dは、街が道路でマス目に区切られていると考えると、ある長方形の対辺に乗っているペアを数えることになる。座標が106以下なのでそのままBITに乗せて、初期化はいちいち更新をロールバックしたが、座圧すれば1マス取得でよかったようだ。縦横両方にするのも少し面倒。

Eは難しい。トーナメント表の半分ずつ(準決勝の2分の1、準々決勝の4分の1……のこと)をsetで全通り計算するコードを書いてみたところ、k\le 4は爆速で終わるが、k=5のときが間に合わない。setに直接insertするのではなく、いったんvectorに溜めてみたところ、手元で4secをギリギリ下回ったが、CF環境が信頼できないので、もう少し根本的な改善をする必要があった。実は全通り計算するのは下からk-1段目まででよく、k段目については値の存在判定さえできればよい。ということで最後の段を特別扱いすることにしたら、k=5の場合もk=4までの計算で済むので爆速になった。

Fは、文字種を座圧したものが15万通りくらいしかないようなので、それを全探索するのかとも思ったが、毎回の判定が間に合わない気がして、一気にdpで計算するのかと考えていたら、コンテストが終わってしまった。TLを見た感じ、全探索した後毎回判定するので合っているらしい。

今日は結局インターンの業務を進めることができなかった。現実逃避のためにECR17を埋めた。

Dashboard - Educational Codeforces Round 17 - Codeforces

Aは、制約からO(\sqrt n\log n)を落とそうとしているのかと思い、O(\sqrt n)で解いた。約数列挙をすると、昇順の列と降順の列に分けて得られる。Bはソートして貪欲だが、実装ミスのWAを勘違いしてコードを大幅に書き直す羽目になった。Cは左と右から必要な文字の範囲を前計算して、被らないように尺取り。区間の端を含むかどうかの処理で結構サンプルを合わせるのに手間取った。Dはヤバそうな見た目をしているが、実際のところたった5通りの状態に対する遷移を全部書き下せば終わり。Eはfごとにまとめてその個数ぶんのBITを作り、取得を区間和で行う。x+rを昇順に持っておいて適宜個数を引いていく。

Fはヤバそうな見た目をしているが、木dpを書くときれいに遷移してくれて、特段変わった処理をする必要はない。Sに含まれるTを頂点のラベル付きで数えた後、Tに含まれるTを全く同じコードで数えて割ることでラベルなしの数え上げをするのは、半信半疑で動かすとちゃんとサンプルがあって感動した。ところがTLEが取れない。ケースを見ると、大きすぎて上のほうしか確認できなかったが、どうやらウニグラフで落ちているらしい。そこで手元でちょっと試してみると、ウニの中心が適当に設定した根以外の場所だと一気に処理が重くなっていた。次数が一番大きな頂点を根として扱うことにしたら、爆速で通った。想定解でも木の中心を見つけるということを行っているが、その後重複を省く方法が、割り算ではなく頂点の割り当てを一意になるようにルール付けするものだった。

午前4時前になって、ようやくゲノコン2021のD問題が公開された。問題文がかなり厳つくて、これまで3問の練習問題がなければ確かに参加者は大幅に絞られただろうという気になる。というか、僕はかなり絶望していて、C問題も2700点くらいを出す提出のブログ記事を読んだのに結局何もやっていないため、これから触れることはなさそう。

Genocon2021 ー DNA Sequence Analysis Challenge - AtCoder

朝方、ハーメルンの捜索掲示板をいろいろ見ていた。自分の大好きな作品で検索したりするのも面白い。自分の好みのジャンルについての捜索が出されているのを見て、いっちょリストアップしてやるかとも思ったが、大抵は過去の似たような捜索で出ている作品であるから、別段自分が言う必要性もないな……と思って止めたりしていた。布団に入ってからもしばらくハーメルンを読んでいたが、午前8時過ぎに寝落ちした。

09/09(木)

午後3時すぎに目を覚まし、またハーメルンを読み始めた。午後4時半に1作読了。「俺の家が幻想郷」。

syosetu.org

良かった。オリキャラの名前や最初数話の文体からいかにもな厨二臭さを感じるが、設定が良いためあまり気にならなかった。ミニチュア東方キャラとかいうどう転んでも健康に良い設定、素晴らしい。同作者の別作品に主人公が同じ名前のこれまた東方2次創作があったが、そちらはシンプルなオリキャラ幻想入りであまり興味を惹かれなかった。

続いて別作品を読み始め、午後6時にさらに1作読了。「美少女精霊たちに愛されたいと頑張ったら最強の精霊使いになっていた」。

kakuyomu.jp

無双ものを期待し、実際に無双していたのだが、主人公のどういう点が周りと違うのかは説明されていても、それがどのように強さに影響してくるのかにはほとんど理由付けがないように感じられた。まだ物語が始まったばかりだからだろうか。主人公とヒロインの絆を描くストーリーも、クライマックスのバトルシーンもいい感じではあったが、自分の最近の好みに特別当てはまっているわけではない。

またハーメルンの捜索掲示板に戻って東方の2次創作を探す。いくつか良さげなものを見つけては数話読んでやめる、を繰り返していたら、読み進められそうな古代スタートものを1つ見つけた。それを読み始めたが、午後9時半くらいに寝落ちした。

目を覚ましたら午前1時だった。昨日インターンの業務が一切行えなかったのを気にしていて、今日は頑張ろうと考えてはいたものの、ふたを開けてみれば夜中までずっと寝たりハーメルンを読んだりを繰り返していただけ。これはひどい。慌てて起き上がり、とりあえずatgolferの更新を確認してしばらくコードゴルフしていた。HikakinTVに短い動画が上がっていて、以前「チャンネル登録者数995万人から1000万人到達するまで生配信する」と宣言していたが、いつの間にか996万人になってしまったので土曜の昼間から生配信する、ということを言っていた。僕もチャンネル登録した。

午前3時から業務開始。今日はちょっとしたコードを書いた後pytorchのexamplesからおすすめされたコードを読んでいた。午前6時で上がり。

また少しコードゴルフをした。起きてすぐ書いたコードが縮められていたので、縮め返した。

atcoder.jp

81B→80B→79B。明らかな短縮ポイントがずっと残っていたが、ここを縮めると50msくらいTLをオーバーしてしまうようだった。Vimの補完の際にめちゃくちゃ長い文字列が候補として挙がってしまうのが問題。何とかして実行時間を縮められないかといろいろやってみていたところ、数値をコードに直接埋め込むこと、うまいこと改行を残すこと、掛け算の順番を変えることで数回に1回2000msを切るようになった。4ケースTLEしているので、全部2000ms以下に揃えるのは厳しいかと思いつつ提出したところ、1発で見事に通った。1つのテストケースに対して最大3回実行されるということもあるし、思ったより確率は低くなかったのだろう。とはいえ、その後3回出して3回ともTLEしているので、やはり運が良かったのは大きいか。

CFのTシャツをもらうためにsettingからADDRESSを埋めた。SOCIALという部分にも個人情報を書くべきかと思ったが、必要ないらしい。シャワーを浴びてゴミ出しし、ちょっとだけKaggleを進める。スコアの良い公開提出をコピーしてきて、自分で動かしてみていた。ここに自分なりの特徴量を増やしてうまくいけばスコアがよくなるということらしい。submission.csvを見ると、これまで自分が提出してきたものより行が多くてびっくり。自分のコードのどこかが間違っているのだろうか。それにしては、なぜ正しく採点されているのだろう。よくわからないが、その違いを見極めるには微妙に眠気があるので、今日は寝ることにした。

布団に入ってうっかり1時間ほどハーメルンを読んでしまう。明日は午後3時半から1on1で、この2日間の無みたいな進捗をメンターさんにお伝えしなくてはならない。起きられるよう祈りながら午前11時就寝。

09/10(金)

午後2時半の目覚ましで目を覚ましたが、あまりにも眠すぎるということで30分二度寝する賭けに出た。勝利して見事午後3時に起床。

YouTubeを見たら、HikakinTVのチャンネル登録者数が1000万人を超えていた。生配信はどうなったかというと、今日の昼ぐらいに急遽行ったものの、20分もせずに到達してしまったらしい。アーカイブを見たところ10分弱で1万人増えるというとんでもないペースで、HIKAKINのすごさを思い知った。本当は僕は、5万人増えるのに何日かかるんだろうかとかそんな長いこと配信できるのかとか、いろいろ心配していたのだが。

HIKAKINのこれまでの道のりを詳しく知っているわけではないのだが、より一般に、人が感極まっている様子に弱い。今日のHIKAKINは、直前まで普通の声だったのが、感情がある閾値を超えた瞬間に急にヘロヘロになるという、特に理想的な感の極まり方をしており、何度見てもうるっとくる。

午後3時半から1on1。今週は稼働時間としてはほぼ無だが、一応1on1の度に1段階以上業務を進めている。個人的にはたった数時間コーディングして終わるようなことは大した進捗ではないと考えているが、メンターの方からは思ったより進みが速いと言っていただいて、嬉しくなった。調子に乗らないようにしたい。進捗報告の後はこの後数日やることの確認を行って、1時間もせず終了。

様々な物事に対するやる気がちょっと出てきたので、メールを2通書いた。1つは4年ゼミの先生宛で、長期インターンを開始したことの報告。もう1つはサークルの顧問教員宛で、サークル代表を交代することの報告。さらに代表者交代届をまだ提出していなかったので、自分の分を書いて新代表に残りを埋めるようお願いしたりもした。これはここ数日やるべきこととしてずっと頭の中にあったので、解決できて満足。

夜、学食に行こうとしていたらインターン先からパソコンが届いた。ワクワクしながらとりあえず学食で夕食を食べ、帰ってきて開封

周辺機器は、会社のお金で買うこともできないことはないらしいが、その時はパソコンとともに会社に返却することになるので、自分で買って使うことにした。明日あたり早速買いに行きたい。キーボード、マウス、LANケーブル、延長コードは必ず必要なもの。あとはモニターとモニターアームも欲しいので、机の寸法など図ってから電気屋に行こう。寸法を測るためのメジャーが家にないため、それもまず買っておかなければならない。

今日はとりあえずパソコンのセットアップだけでもしておくかと思って、モニター1枚のケーブルを移し替えて起動してみたが、LANケーブルがないとネット回線に接続できなかったので、諦めた。

しばらく日記を書いてから、yukicoder 313に出た。全完。

yukicoder contest 313 - yukicoder

Aはよい。Bはびっくりするが、制約がギャグなので愚直に解ける。CはどのA_iでも立っていない最小のbit。Dは区間setの遅延セグメント木を書きかけたが、priority_queueでシミュレートして区間minのセグメント木でチェック、でよい。Eはdp。Fは構文解析。Gは、Eの考察をさらに進めると、買う・1回交換する・売るを繰り返すことになるのがわかり、最小費用流で解ける。つい最近もABCで最小費用流を見たので、しばらく無意識的に考察から除外していたが、作問者のツイートを見るにこの問題を作ってからABCで出たという流れだったらしい。負辺があるが、除去せずDAG上のDPでポテンシャルを求めて解いた。

しばらくパソコンの前で、朝方からは布団に移動して、ずっとハーメルンを読んでいた。東方オリ主古代スタートもの。オリ主が幻想入りする直前の現代の風景がかなり好みで、ちょうどそのあたりに差し掛かったので、舐めるように読んでいた。幻想入りしてから原作キャラと再会するシーンも好きだが、そのあとはだんだん興味が薄れていきがちなので、どうしようか迷う。最近読んでいた作品はこれ。

syosetu.org

午前7時くらいに就寝。明日は買い物。

09/11(土)

午後3時、起床。すぐに準備して、地下鉄に乗って駅前まで出る。

まず、ヨドバシカメラでLANケーブル・延長コード・キーボードとマウスを揃える。今使っているマウスがトラックボール式なのでできれば揃えたいと考えていたが、結構いい値段がするので、あえてガラッと変えてタッチパッドのついたキーボードを購入した。それでも4000円くらいしていたが、トラックボールマウスを買うよりは安いので即決してしまった。あとは前から欲しいと思っていたエアダスターも買って、合計1万円弱。ヨドバシカメラのポイントカードを出したら、クレカ機能が付いたカードに交換しないかと言われ、まあ勝手にやってくれるのなら……と思って頷いたら、機械の前に案内されてさあどうぞ!と言われキレそうになった。

実際にキレることはなくて、唯々諾々と個人情報を入力していたのだが、現在持っているポイントカードと情報が合わないらしい。店員さんが調べに行ってくれたところ、どうやら実家の情報が入力されていたようだ。ポイントカード自体も実家に届いてしまうらしく、さすがに面倒が過ぎる。このあたりで勇気をもって「やっぱりいいです」と伝えることができて、無事会計に戻った。そもそもヨドバシカメラは年に1回行くか行かないかのペースなので、ポイントが失効する前に使えた試しがない。還元率がどれだけ良かろうと無駄。

続いてモニターを選ぶ。ヨドバシカメラにもモニターやモニターアームが置いてあったが、なんだか思っていた値段よりも高い。モニターにスピーカーが付いている必要はないので、そういうものを売っていることが期待できるパソコン専門店、具体的にはドスパラのほうに行くことにする。が、ドスパラにもスピーカー付きのモニターしかなかった。

モニターアームについて店員さんに相談してみた。すでにディスプレイを置いていて、それの上に並ぶようにモニターを設置したいと言ってみた。可能ではあるようだが、ちょっと製品を選ぶ必要があるらしい。ポールを立てて、そこからさらにガス圧のアームを伸ばすようなものなら大丈夫だろうとの話。また、2枚設置したいということを言ったら、1枚用のものを2つ買うのもアリだと言われた。ともかく、目的に合致するものは実店舗には置いていないので、結局はネットで注文するのがよいとおススメされた。

仕方ないので帰る。せっかく駅前まで来たということで、スマホアームを設置している店舗に行ってチュウニズムの手元を撮影してきた。以下のリプライツリーにまとめてある。

帰ってきてすぐ製品を選ぶ。モニターアームは、結局2枚縦に並べられるものを2つ買って使うのが間違いないと思った。買ってから気づいたが、僕が選んだ製品だと上段のモニターが下段のモニターより奥に行ってしまうかもしれないし、さらに上にだけモニターを取り付けたアームは重心的に不安定で危険な気がする。肝心要のモニターは、15000円くらいを想定していたつもりだが、どうやら20000円を切る製品すら限られてくるようだ。サイズも決めていなかったのでかなり迷ったが、結局↓のモニターを2枚購入した。そこそこ大きくてそこそこ安く、VESA規格に対応しているのでちゃんとモニターアームに設置できる。

Amazon | HUAWEI モニターディスプレイ Display 23.8(23.8インチ/IPS液晶/解像度1920×1080/1年基本保証+2年無償延長保証/HDMI/ブラック)【日本正規代理店品】 | HUAWEI(ファーウェイ) | ディスプレイ 通販

あとはパソコンと接続するケーブルを1本で、総額45000円弱。競プロの賞金として得たAmazonギフト券で支払える額だったので、拙速を尊びそれで購入した。代わりに振り込みのためATMから降ろしてきたお金の行き場がなくなったので、また戻しておこう。これまでのお金遣いからするとかなり散財したなという印象だが、インターンでこれ以上の金銭を得られる予定なので問題ないはず。金銭感覚が追い付いていない。

モニターを選んでいるということをツイートしたら、某競プロerさん(匿名希望)からAmazonギフト券7000円分(も!)を送ってもらった。かなり突然のことで、非常にありがたい一方、こんなに貰って自分は何を返せるのかという気持ちになった。とりあえずメンションなど飛ばして感謝の気持ちを大々的に伝えようとしたが、匿名希望らしい。心の中で本当に感謝しているということを、ここにも再度記しておきたい。

午後9時からABC218に出た。6完。もう完全にダメ。

AtCoder Beginner Contest 218 - AtCoder

Aはよいが、短い書き方となるとわからない。BはPerl、そのあとRakuで出しなおした。CはC++で、愚直O(N^4)しか思い浮かばなかったので出したら1200msくらいで通った。結構攻めた制約だな~などのほほんと考えていたが、これが想定なわけはない。Dは座圧した後xを2つ選んでbitset。4secなので自信を持って出したが、これも想定ではなかったようだ。Eは打って変わって非常に簡単、最小全域木っぽいことをやるだけ。Fはなかなか難しくて、迂回路があるかどうかなど考えていたが、しばらくして答えに影響する辺が高々N-1本しかないため、毎回計算できることに気づいた。

Gが解けなかった。二分探索を一生考えていたが、全然合わない。最後に出した提出は2分探索を2重に行っていて、2ケース落ちた。8問体制になってからABCの600点に苦手意識がついている気がする。何とかしなければならない。

TLをチラッとだけ見たが、二分探索ではなかったらしい。それでさらにしばらく考えたら、ふとdfsを1回するだけで各葉に対して中央値が求まることに気づいた。それからも結構WAを重ねて、ようやく解けた。僕は優先度付きキューを2本持って、取り出したときにすでに考慮しない要素だったら無視する方針で書いたが、解説のようにmultisetを使って直接削除するほうが簡単か。さらにH問題を考えていたが、TLをちらっと見た瞬間にちょうどAlienDPとのキーワードが流れてきてしまった。まあ自力では不可能な気もする。upsolveは後回し。

コードゴルフ。AはVimを書いていたが2B負け。BはRakuに満足していたら普通にdcで縮められた。Cは面倒そうだなと思っていたところ下のHaskellコードがatgolferに流れてきたので、Rubyに直して縮めた。

atcoder.jp

Dも僕がコンテスト中に書いた方針(xを2つ選んでyをカウント)をRubyで書いたが、解説の左上と右下を固定する方針を試していないため縮むかもしれない。pythonはその方針で書かれているようだ。EはPerl。0とのmaxを取るのは$-に代入するしかないと思っていたが、先頭に'0'を加えて数値として解釈してもできるらしい。そちらの方法だと空白を1つ省けて縮む。以降は手付かず。

午前2時からFHC2021 R1に出た。

Facebook Hacker Cup - 2021 - Round 1

24pt取れば通過できるらしい。僕はA1A2A3とBを解いた。

A1はまあ、できる。A2を考察するときにA1をもう一度よく考えると、これはつまり'F'を無視したときに'X''O'が隣接するような場所の個数だとわかる。それを用いると、逆に隣接する'X''O'を両方含むような部分文字列の個数だけ答えが増えるということになって、A2が解ける。A3のため、さらにA2を考えてみると、だいたい\sum l\times rという値を求めていることになるが、実はこの値は加えて\sum l\sum r\sum 1、文字列の長さを持っておけば文字列を2倍する操作に対しても更新が可能。間で1つ増える可能性があるが、これは一番左・右にある'F'でない文字を追加で持っておくことで求められる。オーバーフローしていたがvalidationで落ちてくれたので助かった。

A3を解く前にBを解いていた。しばらく考えていたが、実はギャグで、左上と右上の値だけ増やせばOK。

朝方布団に入ってハーメルンを読む。案の定昨日まで読んでいた作品は微妙に飽きたので、別のものを1つ。しかしよくわからなかった。

syosetu.org

別の作品、これもまた東方オリ主古代スタートものを読み始めたり、過去に読んだハーメルンをちょっと読み返したりして、午前9時に就寝。

09/12(日)

午後4時半に起床。午後5時からOpenCupに初参加した。何のリンクを貼っていいのかわからないので、とりあえずCFで議論していた場所を貼っておく。

XXII Open Cup, Grand Prix of Dolgoprudny - Codeforces

ヤバかった。赤3人で組んで5完だが僕自身は1問も通せなかった。前のほうの問題を読んで概要をまとめていたが、どうやら非人間向けだったらしい。考察した問題はDとKで、DはMo's AlgorithmにsetのlogをつけてTLEしていたのを、チームメイトがvan Emde Boas treeでぶん殴っていた。Kは最終的に98チームが提出してAC数2という化け物で、僕も見た目が簡単なのに騙されて適当な解を投げ、考察を進めるたびに難しさを実感して結局放り投げた。他にチームとしてACできた問題は、そもそもまともに考察していないので、upsolveも何もあったものではない。

CFブログにあったDの解法は頭が良い。Mo's Algorithm中で自分より小さい要素の最大と自分より大きい要素の最小を取りたい。結局謎データ構造で\log\log Nになったが、実はDancing Linksを使って線形時間でできるようだ。削除を巻き戻すため、更新順序を良しなにしなければならない。どうするかというと、まずクエリのlでブロックに分け、各ブロックでデータ構造を初期化する。rの昇順に並べるのはMo's Algorithmと一緒だが、lのために毎回ブロックの先頭からlまで進めて(削除して)、クエリに答えたら即座にブロックの先頭まで戻す(削除を巻き戻す)のを繰り返す。Mo's Algorithmの計算量解析からして、このように無駄な操作を行っても高々定数倍しか変わらない。Mo's Algorithmの更新順をいじることで操作を単純にするのは見覚えがある気がする。

5時間椅子を温め続けた。終わってすぐTOYPROのコードゴルフ大会に30分だけ参加した。

TOYPRO(トイプロ)

なかなか独特な競プロ体験だった。問題文で与えられた変数を使って、サンプルを埋め込んだようなコードを書いて提出すると、対応する変数名の変数にテストケースの内容が代入されてジャッジされるようだ。しかし同時に、代入しない状態でのジャッジ(正常に実行が終了するか)も行われるようで、変数だけ用意していると落ちる。ほかの人のコードを見たわけではないので何とも言えないが、自分は用意した変数を即座に1文字変数に代入してコード長を削ったりした。

1問目からマルチバイト文字を扱っていてびっくりするが、どうにかこうにか2問目から5問目までゴルフっぽいことをして提出した。しかし順位表を見ると、どの問題もより短いコードが存在していたらしく、悔しい。

日本橋ハーフマラソン2021 増刊号が終わっていた。結局、火曜日の提出が最後になって、システムテスト前の順位は100位まで下がってしまった。終わった時間にTLを見ていなかったので解法を終えていないが、どうやら評価関数をうまく設定してビームサーチする問題だったらしい?僕のコードは評価関数が重すぎてただの貪欲が精いっぱいだったが、遷移を絞り込むと幅を増やせたのかもしれない。コードゴルフとしては-1で埋めるのが短いが、この問題では1000行より多く出力していてもACとなるらしい。sedc-1が最短となった。

ACPCの参加登録が始まっていたので、申し込んだ。

ACPC 2021(会津大学競技プログラミングコンテスト 2021) - connpass

午後11時半からCF CGR16に出た。

Dashboard - Codeforces Global Round 16 - Codeforces

ABCdDEFGを解いて12位、レートは2823→2952(+129)でhighest。大成功だった。

Aはよい。Bは2が必ず達成可能なので0と1を判定すればよく、簡単。Cは(0,1)を必ず切り離して、(1,1)(0,0)が隣にあったらそれと組む。どちらも左から貪欲に求められる。Dは、D1もD2も座る場所を貪欲に決めることができる。答えを求めるときは、毎回O(m)かけても間に合う制約だが、一応BITを作った。Eは葉からどんどん切り離していくとして、最終的にどこに繋げるかは考えなくてよい。

Fは、初期状態ですでに条件を満たした区間を取り除いて考えると、各aで分割された間にいくつかの区間が挟まる形になるので、そのまとまりごとに「左からいくつを左のaで取るか」を考えてdpする。dpのキーは、左右にあるaを自由に動かせるか、あるいは元の位置に戻す必要があるかの2×2通りだけ。実装を簡単にするために左右に番兵を入れたが、その値をintに収まるよう\pm 2\times 10^9にするとマズそうなので、わざわざlong longを持ち出してこなければならず、大変だった。

Gは面倒。辺を短い順に4本取ってきて、それぞれ1234とする。12が端点を共有しないなら、それらが答えになる。そうでなくとも、この4つの辺のどれか2本は端点を共有しないことがわかるので、考えるべきは(3,4)の組より長さが短いものだけ。それはどんなものかというと、*を1本の辺として(1,*)または(2,*)または(1+2,*)に限られることがわかる。ここで1+2は2本の辺からなるパスで、(1,2+*)(1+*,2)も適当に組み替えると(1+2,*)にできる。つまり、いまある辺のうち端点がuでもvでもないもののうち最短のものが取得できればよい。各頂点に対し、そこから出る辺(ともう一方の頂点)を短い順に3本保存してセグメント木に乗せて解いた。2つのデータのマージは、辺の先の頂点が重複しないように注意して計算する。辺の追加は簡単で、削除については、各頂点に対して優先度付きキューを持っておいて、そこから上位3つを改めて取り出す(削除された要素は無視)ことで再計算した。この部分については昨日のABC218-Gのようにsetを使ったほうが楽だったかもしれない。

Gのシステムテストが750ケース以上あってびっくりした。

FHCが終了した。出したものは全部通っていた。Cもちょっとばかり考えていたのだが、C\le 20という制約に気づいておらず諦めてしまった。また順位表にそこそこTimer Expiredがいたので何となく予想はついたのだが、手元で実行してstack overflowした人が多かったらしい。beetさんのブログに回避方法が書かれていたはずだが、もう見ることはできない。

HikakinTVに生配信直後の様子を撮影した動画が上がっていた。そのうち以下のシーンについて。SEIKINがHIKAKINのために急いで買ってきたケーキの話で、HIKAKINが「ホールじゃん」と言ったのをSEIKINが「当たり前だろ」と言ったのがかなり印象に残った。また店頭で頼んで文字を書いてもらったからSEIKINだとバレバレになったりしたことも面白い。

朝方日記を書いている最中にABC218-Aが縮んだ。今回の問題は'o''x'を区別する問題で、たまたま'No'には'o'が含まれ、'Yes'にはどちらも含まれない。というわけで、'Yes No'という文字列を用意し、Yesの上にカーソルがある状態で'o'または'x'を検索すると、'o'の場合はNoにカーソルが移り、'x'の場合は移動しない。その後カーソル下の単語を消せば答えが得られるという寸法だ。

atcoder.jp

週記(2021/08/30-2021/09/05)

08/30(月)

先週の週記は、文章を書きながら意識を飛ばしそうになっていたので、投稿してからは比較的すぐに布団に入って寝た。午前6時半だった。

途中、午前11時くらいに目を覚まして、ちょうど届いたAmazonの定期購入の荷物を受け取った後、少し布団でゴロゴロしていた。この時間に起きたら学食に行けるなあとか、注文した本が生協に届いたようなので受け取れるなあとか、そのようなことを考えていたが、結局また寝入ってしまった。

次に起きたのは午後6時くらい。寝ている間にSlackでDMが来ていて、sotanishyさんが次代のサークル代表に立候補してくださった。一応サークルの規則で、総会を開いて代表を決定することとあるが、正直そのためだけに通話をホストしたりするのはコミュニケーションコストが高いと感じているので、Slackのリアクション機能を利用した信任投票で決を採ることにする。コロナ前の碧黴さんが代表の時代は、通話で会議した記憶もあるし、僕自身借りた教室に集まって開かれた総会で代表に決定した経験もあるが、このあたりの文化はだいぶ消し去ってしまった。

atgolferの更新を追いつつコードゴルフする。最近あまり週記で触れていないが、今でもatgolferは数時間に一度確認しているし、短縮されたら取り返そうと努力している。今日も2つ更新されていて、1つは取り返したが、もう1つはどうにもうまくいかない。僕が初めに書いていたコードから変わっていない部分があって、そこは短時間で思いついた書き方なので縮みそうな感じはしていたのだが、思ったより頭が良かったらしい。

リストの途中の連続部分列を取得したくて、ただし取得したい位置が空の場合もある。このとき、例えばarr[3..2]は空のリストになるが、arr[3,-1]nilが帰ってきてしまう。また実は先頭にいくらかパディングしてarr[3..2]とできているのであって、本来はインデックスから3引いてarr[0..-1]という感じになるが、これだと-1がリストの末尾要素を指していると解釈されて、arr全体を取得してしまう。どうにも上手くいかなかった。

先週のABC216-Dの嘘解法が流れてきたので、縮めておいた。1回でも操作できること、つまり先頭要素に重複があることと、同じ筒の中に重複した要素がないことの2点を確認すれば通るらしい。

Submission #25466179 - AtCoder Beginner Contest 216

7セメスターの成績が出たので、いつも時間割と成績をツイートしているリプライツリーにつなげておいた。このリプライツリーももう3年半。こうやって何年も同じことを続けていると、いよいよTwitterアカウントが2つとない、失ったら最後取り返しのつかないものに思えてくる。もし今後何かの間違いでこのアカウントが凍結されたりしたら、自分はどうなってしまうのだろうかと、以前から不安に思っている。

先週金曜日のyukicoderのC問題の解説を見て、解いた。これはコンテスト当時思いつかなかったのだから仕方ないだろうという感じがあるが、もしこれがRatedに出て大敗を喫したらたまったものではない。

#694290 (Ruby) No.1658 Product / Sum - yukicoder

次に、こちらも解説を読んで、ARC216-Hを通した。

Submission #25470126 - AtCoder Beginner Contest 216

LGV公式ということでしばらく考えてみたのだが、自力では超大量の行列の行列式の総和を求められなかった。行列式の線形性というのは、各行各列に対しての概念であって、全く異なる2つの行列の和を考えられるような概念ではなかった。行列式には様々な意味づけがあって、この問題では置換による定義を採用して計算している。ARC054-C「鯛焼き」では、逆に置換による定義を使って問題を行列式の計算に落とし込み、計算は別の方法を採用していたので、対照的とも言えそう。

さらに置換を全探索して計算することにした後もいくらかステップがあり、順列ごとのdpを考えた後bit dpですべての順列をまとめて計算するくだりなどは、置換の符号もbit dpでちゃんと計算できる点など非常に美しいと感じた。出来上がったコードが非常にシンプルだったのも良い。総じて、凄まじい問題だった。

それからはしばらく本を読んでいたが、疲れを感じて布団に移動すると一気に眠気が襲ってきて、生活リズムの是正も考えて素直に寝ることにした。午前1時前だった。

08/31(火)

午前8時起床。

そのまま布団で、昨日読んでいた本を読み切った。「かくりよの宿飯」1巻。先週古本屋でシリーズ11巻をまとめ買いしたものに手を付け始めた。この作者は「浅草鬼嫁日記」で初めて触れて、本の内容というよりは設定や見せ場の作り方が好みと合っていたので、それ以来ほかの著作にも少し手を出していた。最初はファンタジーの本を書いていたようだが、人気シリーズは今名前を挙げた2つで、どちらもあやかし関連の話だ。ちゃんと面白かったので、今後の展開も楽しみ。

昨日嘘解法で縮めたABC216-Dがさらに縮んでいた。見た感じさらに条件を弱めたというか、そもそも先頭要素の重複があることをチェックする代わりに特定の文字列があるかをチェックしていて、いよいよテストケースハックの本領発揮といったところ。さらにafter_contestが追加されたらしく、もう縮むことはないだろう。まあこれもAtCoderコードゴルフをする宿命か。

学食に行って昼食を摂り、注文していた本を受け取った。今日は6冊。どれもかなり楽しみにしていた本なので、早く読みたいところだが、昨日から手を付けたシリーズも読みたい。どうすればいいものか……。

とりあえず今日買ってきた本の中から「現代社会で乙女ゲームの悪役令嬢をするのはちょっと大変3」を読み始めたが、昼下がり急に眠くなったので、耐え切れず布団に倒れこんでしばらく寝た。

午後1時くらいに意識を落として、次に目を覚ましたのが午後5時だった。アナログ時計は午前午後がわからず、外が微妙な明るさだったため、さては朝の5時か!?と思ってうろたえたが、ちゃんと確認すると全然そんなことはなくて一安心だった。

そのままずっとラノベを読んでいたが、午後8時半くらいになって、昨日サークルSlackに投稿した新代表のアンケートの信任が過半数を超えそうになっていたので、アカウントの権限付与などの作業をsotanishyさんと一緒に行った。特にGmailアカウントは、一度ログインしてもらってこちらから認証しなければならないため、2人の手が空いているときに行ってしまう必要があった。それ以外は順調に進み、定期的にサークルのメアドを確認してもらうことだけ伝えて終わり。ICPCICPCの、新歓は新歓の時期にまたいろいろ伝えることになるだろうが、通常の業務はこれくらいとなる。

日付が変わったあたりで「現代社会で乙女ゲームの悪役令嬢をするのはちょっと大変」3巻を読了。今巻も非常に面白かった。単純なのでお嬢様が表舞台に立っているだけで面白く感じられて、その意味では今巻の卒業コンパのシーンや、特に桂華タワー落成式のシーンはWeb版から好みの部分だった。恋住政権が発足してから、以前のように政治にバリバリ関わることが難しくなったお嬢様だが、今後も経済のほうで活躍する姿を見たい。

明日から始まるインターンの初日の予定がメールで知らされた。同じ時期に業務を開始する面々や社員の方々との顔合わせ、社長からのお話もあるため、ありったけの社会性を用意して臨みたい。

布団に入って少し本を読んだが、すぐにやめて午前4時就寝。

09/01(水)

午前9時半起床。急いで食事し、オンラインの入社式に備えて上半身だけ着替えたりノーパソを壁に向けたりしていたら、ギリギリの時間になった。

午前10時から開始。全体向けの会社の説明、個人向けの説明、インターン受け入れ先の部署とお話、メンターの方と1対1でお話、と今日は一日喋る日だった。一応仕事に参加するにあたっての必要最低限のアカウントをセットアップしたりはしたが、逆にそれ以外何もできていないのに金銭が発生しており、かなり困惑する。早く成果物を作り出したくてたまらなくなってきた。午後7時で上がり。

終わってからしばらくは微妙な眠気で動けなかったが、何とか身を起こして学食に夕食を摂りに行った。帰ってきてからは本を読んだり動画を観たりしていた。

TSGがAnarchy Golfを使って小さなゴルフ大会を開いていた。特に参加はしなかったのだが、一応問題だけ見ると、コラッツ問題で与えられた数が1になるまでの経過を出力せよという問題だった。dcのコードが提出されていて、念のため確認したところ、これまでAtCoderで僕が使っていたコードより1B短くなっていることに気づいた。かなりびっくり。焦って2問ほど縮めた。

http://golf.shinh.org/reveal.rb?Collatz+Problem/tails+%28Carlos+Gutierrez%29_1332227477&dc

Anarchy Golfにいつの間にかJellyが入っていた。Unicodeで見ないと何もわからない。わけのわからなさでいえばgs2も似たようなものだが、Jellyは一応Unicodeの形に基づいて設定されているような命令もあるから、そこの違いは大きい。

しばらくなろうを読み返していた。以前に読んだなろうは、自分の好きなシーンだけつまみ食いすることができるので、読み返すのは結構好きである。実家にいるときはラノベもそうやって少し読み返したりしていたのだが、仙台に来るときに既読本はほぼ置いてきたし、今は数か月おきに読み終わった本を送り返さないと本棚に入らなくなってしまうので、ラノベを読み返す機会は帰省のときのみと極端に減ってしまった。

8月の読書記録をツイートした。先月は結構頑張って読んだつもりだったが、それ以上に本を買ってしまった。まあ、本は買えば買うだけよいということを常々思っているため、問題はない。

布団に入ってしばらく本を読み、午前1時半就寝。

09/02(木)

午前11時起床。午前10時からSRMがあったらしいが、さすがに早朝すぎて不可能だった。着替えて学食に行く。雨が降りそうではあったが、天気予報は40%だったのでそれを信じ、原付に乗って行った。この時間帯は道が混んでいないため、自分のような怖がりでも乗ることができる。

1万円札の新しいデザインが発表された発表されたのではなく印刷が開始された(2021/09/06追記)。以前のデザインは2004年から使われていたらしい。ところで、1万円のことを諭吉と呼ぶのはかなり自然な表現に感じられて、実際本などでもたまに目にすることがあるが、これは1万円札の肖像画福澤諭吉になってから登場した表現だったのか。たった17年前のことだとは思えないくらい広まっている……というようなツイートをしたら、実はその前の1万円札から福澤諭吉だったらしい。1984年からで、都合37年間だった。それなら納得だ。

今日は午後1時からメンターの方とまたお話をした。実は昨日のうちに、この後しばらくやることを決定していて、それに関することを重点的に話した。また更にいくつかのサービスでアカウントを発行してもらい、いよいよ自分の手元にコードを落としてきて動かしてみることになった。ちょっと環境を整備した後、さらに別の人と話す必要性を確認して、そのためのミーティングが明日にセッティングされ、今日は終了。午後3時だった。手元にデータを落としてくることくらいはもう可能なので、そういう準備をできるだけ進めておく。

思ったよりバリバリ機械学習をすることになりそうでビビっている。メンターの方に手ほどきを受けることになっているが、さすがに基礎的な事項くらいは自分で抑えておくべきだと感じ、とりあえずKaggleにアカウント登録をした。コースがいくつか用意されているので、これを手当たり次第に埋めていこうと思う。まず最初にPythonのコースを終わらせたが、さすがに全部既知の事項だった。最後のボーナスレッスンでTitanic Tutorialというコンペに提出を行ったが、今度は逆に知らないことだらけだった。どこからランダムフォレストが生えてきたのか一切わからないが、とりあえずデータは生まれたので、提出できた。

次にIntro to Machine Learning。こちらは結構勉強になった。いろいろなブラックボックスの使い方を学んでいて、中身が知りたいという気持ちもあるが、実際のところ機械学習の詳しいアルゴリズムを知らないと、むしろ知っていてさえ中身を見てもどうしようもないだろうとは思うので、とりあえず今は何があって何ができるかを知っていきたい。pandasのDataFrameをいろいろいじくりまわしているが、かなり柔軟な使い方ができるようで、とりあえずそれを重点的に学びたいとの思いから、次のコースはPandasにした。

このあたりで、改めてインターンのための環境構築を進める。pythonの必要なモジュールをpipで入れる作業をしていたら、どうにもtorchとtransformersがエラーが出て入らない。こういうときはエラーで検索すればいいんだ!と思ったが、見るとPythonのバージョンを下げましょうと書いてあったり何も出てこなかったりして、非常に難しい。やはりcygwinでやっているのが悪いということで、これを機にWSLに乗り換えることにした。

WSLを入れて環境構築。といってもcygwinの設定をいろいろコピーしてくるのが面倒になってきたので、WSLを使うのはインターンの間だけということに決めて、とりあえずPythonの環境だけ整えた。ちゃんとtorchもtransformersも入って安心。しかし日本語ファイルが全部文字化けしている!文字コードを変えるのはよくわからないし、いったん全部ダウンロードしなおしかな~とも思ったが、冷静に考えるとフォントが日本語対応していないだけだった。調べると、コンソールで使う日本語対応フォントでRictyというフォントがおすすめされていたので、それを入れておいた。

GitHub - kudryavka/Ricty: Ricty --- fonts for programming

あとは.vimrcを書いたり、カラースキームを適当に決めたりして、何とか見られるようにはなったのではないだろうか。

合間合間で本を読み進め、1冊読了。「かくりよの宿飯」2巻。今巻も面白かった。主人公は基本的に他人(他妖?)を悪く言わないので、そのお人よしさがちょっと気になることもあれど、基本的には好印象。そういうところがほかのあやかしに受け入れられていく様が描かれていて、明るい未来を感じる。

夜中、opencupに参加する集まりに招待された。印象としては、やっとのことで赤の山に登ってみたら、下からは見えなかった頂上に大量の人がいて、みんなさらに上を目指していた、という感じ。りんごさんの名言「赤にいかないうちは、典型も解けていないという証拠なのでどんな問題がでても文句を言わずに解きましょう」が思い出される。つまり、今ようやくある程度の典型を学んでスタートラインに立ったということ。何とか食らいついていきたい。

布団に移動して少し本を読み、就寝。午前6時半だった。

09/03(金)

午後2時起床。午後3時に大学生協が閉まるので、起きてすぐ向かった。昼食を確保するつもりだったがパン類がほとんど売り切れてしまっており、残っていた謎の総菜パンを購入。これだけでは足りないと感じたので、帰りにコンビニに寄って追加で菓子パンやおにぎりを買った。

生協の総菜パンは思ったより美味しかったが、しょっぱいものが美味しく感じられているだけにも思える。塩分不足かもしれない。

インターンの昨日の続きとしては、もう少しミーティングしないと手が動かせなさそうなので、それを待つことにして、Kaggleのコースを進めた。今日はPandasのコース。記法があまりにも柔軟すぎてむしろよくわからなくなってしまった。あとgroupbyの挙動がよくわからない。それっぽく書いたらそれっぽく動きはするのだが、自分で何かをやりたいとなったときにうまくできる自信があんまりない。

午後3時から3時間かけてコースを終わらせると、ちょうどミーティングの時間になった。業務について前任者から引き継ぎを受けるのが1時間、メンターさんとお話しするのが1時間。これまではミーティング以外何もできなかったが、引継ぎを受けて、とりあえず何をやればいいかが何となくわかってきたので、これからは自分でいくらか手を動かすことができる。

またメンターさんとのお話しでは昨日始めたKaggleを話題に取り上げ、Kaggleへの最初の取り組み方のようなふわっとしたアドバイスが欲しいとお願いした。聞くところによれば、僕はコードの読み書きがそれなりにできるはずなので、最初からコンペに出て人々の取り組みを観察したり、提出して自分の順位の変動を見たりするのが良いらしい。そう言われるとかなりやる気が出てきた。

しかしまあ、とりあえず今はインターンのコード読み書きをやってみたいので、そちらに注力する。実行に6分くらいかけたコードが最後のデータ書き出しの部分の文法エラーで落ちてしまって非常に辛かった。ちゃんと小さいケースでテストするよう心掛けたい。そうやって格闘していたら午後9時になったので、中断してyukicoder 312に出た。

yukicoder contest 312 - yukicoder

6完。Aはよい。Bは00が許されていないのに気づかず1WA。ここでk乗根を二分探索で計算するコードを書いたのだが、この後D問題でも使うことになって面白かった。オムニバス形式なので特に意図されたことではなさそう。Cは素因数ごとに独立になると勘違いして1WA、grundy数を直接計算して通した。grundy数はそんなに大きくならないだろうと思って64bit整数のbitを立てつつ計算したが、実際必要な範囲では最大19にしかならないので、これで十分。

Dは難しかった。二分探索をするのはよいが、累乗数を重複なく数えるのに手間取った。最初、素数乗の数を包除原理を用いて数えようとしたが、WA。3乗以上であって平方数でない数を全列挙したあと、改めて平方数を数える(ここで2乗根を計算する)方法で通した。Eはケイリーの公式でM=N-1を計算してそこから戻す……ということを考えたが全然ダメ。しかしケイリーの公式を使うのはよくて、連結成分ごと一気に遷移するようなdpを書いたら3乗になった。Fは隣接する値が異なるマスに対応してグラフに辺を張り、そのDAGの最長パス……としたがWA。隣接していないマスの値の大小関係も保存されなければならないことに気づいていなかった。値が小さくならないようにするには1から順に値を確定していけばよくて、DAGの作り方からこれはトポロジカル順序にもなっているので、正しく定めることができる。

そのあとGを考えていたが解けなかった。この問題にはあまり関係がなかったが、行や列を一気にflipする操作で黒に揃えられるのは全ての2x2正方形で黒マスが偶数個存在することと同値、というのは以前も見た覚えがあるし、ちゃんと覚えておきたい。今日も同じことを考えていたが、証明をつけるのに手間取った。

最近「やばいクレーマーのSUSURU TV」にハマっているが、本人がカバーして動画を出したのを知った。非常に出来が良い。

夜中、またインターンのコードと格闘を再開した。リモートワークでかなり自由度高く働けるので、この時間にコードを書いていても全然平気で給料もちゃんと発生する。かなり楽しい。しかしだんだん頭の働きが鈍くなってきて、この状態でのコーディングに対価が発生するのはなんだか申し訳なくなってきて、午前2時半くらいに切り上げた。

寝ようと思ったが、Kaggleも少し進めておこうかという気分になって、参加するコンペを適当に決めて問題を読んだ。「Optiver Realized Volatility Prediction」というやつで、金融に関する値を予測せよということらしい。データの内容や公式のチュートリアルを読んでいたが、英語にかなり壁を感じた。慣れていないためか競プロの問題文を読むのとは全然勝手が違う。結局最後まで読み切ってもよくわからなかったので、また明日取り組むことにした。

Optiver Realized Volatility Prediction | Kaggle

布団に移動して読書。1冊読了した。「かくりよの宿飯」3巻。冒頭ちょっと剣呑なシーンもあったが、その後は終始のんびりと進行。登場するイケメン男性キャラクターの振る舞いを女性主人公の視点から見て可愛がったりしていた。しかしラストシーンがかなりとんでもないことになって、4巻に続く!と終わった。どうなるのか非常に心配している。

4巻もちょっと手を出して読み進めたが、いい加減眠たくなってきたので、午前6時に就寝。

09/04(土)

午後1時くらいに目を覚ます。二度寝するつもりだったが、うっかりスマホを触ったりしてしまい、そのまま眠れなくなってしまった。今日は生協の冷凍弁当が届く日のようなので、午後3時からは起きていなければならない。布団でゴロゴロしていたが、午後4時くらいになってようやく身を起こした。今日は何をしようかしばらく迷って、Kaggleの昨日の続きをすることにした。昨日はこの公式チュートリアルみたいなものを読んで、読解が終わっていなかったのだった。

Introduction to financial concepts and data | Kaggle

何度か読み直して、ようやく理解できた。10分間の情報が与えられるので、次の10分間についてのある値を予測せよという問題で、チュートリアルの提出では与えられた10分間の情報からその10分についての値を計算して答えとしているようだ。それでも多少のスコアは出る、ということらしい。

やることは分かったので、とりあえず何か提出してみたい。チュートリアルのコードをそのまま出すのも味気ないので、自分なりに何かコードを書くことにした。Parquetという初めて扱うデータ形式が出てきて、あんまりよくわからない。どうやら与えられたデータがあまりに大量すぎて、1度に全部読みだすのはメモリの関係上やめたほうがいいらしく、いくつか区分けされている中で順々に処理していくことになる。

とりあえず1つだけ読み出してそれっぽい特徴量を計算してみた。あとは学習だが、今回は連続値を予測しなければならないので、適当にモデルを調べて、最初に回帰木のランダムフォレストを試してみることにした。その中身については全然知らないが、とにかくfitpredictのメソッドを呼び出してみると、それっぽい値が出ている。csvファイルに書き出して初めての提出を行った。提出してから20分くらい待ったら結果が帰ってきた。

つらい。再度notebookに戻って1文字消し、もう一度セーブして提出。また20分かけて、ようやく正しくスコアが得られ、順位が付いた。チュートリアルのコードよりも精度が悪いらしくてかなり下のほうだが、まあ最初だしこんなものだろう。試しに読み出すデータの区分を5個に増やしたら、大幅にスコアは上がったものの、相変わらずチュートリアルのコードに負けているため、順位的にはほとんど変わりがない。データの区分けは112個あるのだが、5個読み出して処理するのにも2分くらいかかっているので、全部やるのは気が進まない。そういう待ち時間がいちいち発生するのはあんまり好きではない。

スコアを上げる方法が全然わからないので、他の人のnotebookを読むことにした。1回の実行に70分以上かけているらしく、ヤバ……という気持ちになった。そうこうしていたら午後9時になったので、ABC217に出た。

AtCoder Beginner Contest 217 - AtCoder

8問体制になって初めて、ようやく全完できた。

AはAWKがよい。BはRakuで集合の引き算を行った。CはPerl。ABC142-Cとまったく同じコードを書いた。ここからC++で、Dはset。Eはちょっとびっくりするが、優先度付きキューとキューで管理すればよい。Fは区間dp、重複をうまく弾けておらず1WA。各区間について一番左の要素のペアを固定して考えるとよい。Gは、空のグループを許容する場合の数が、あまりが同じ人数などを考えると簡単に求まって(一旦箱を区別して最後にk!で割る)、そこから包除原理で答えを出した。Hはslope trick。maspyさんの記事を読みながら書いた。スタート位置が0と決められていることに気づかず、サンプルが合わなくてしばらく悩んでいた。

atcoder.jp

コードゴルフをする。Aは最初に提出したものが今も最短。Bは文字列のxorを使うのが短いらしい。Cは上の問題の最短コードをコピペ。DはC++を頑張って縮めた。endを指すはずのイテレータにアクセスするとなぜか1が返ってきたので、よくわからないがそのことを仮定したコードを出したら全ケース通ってびっくり。

GをPyPyで縮めているとTOKI Regular Open Contest #22が始まったので、出た。

https://tlx.toki.id/contests/troc-22

5完18位でレートは2588→2596(+8)。途中D問題が解けたときになぜかD問題だけサイトのエラーが出て提出できなくなってしまい、非常にイライラした。それでも何事もなくRatedになってしまい、びっくり。

Aは0があるかどうかを見る。Bはabcabc...を出力すればよい。Cは文字列を2文字になるまで操作した場合のスコアが一意になると気づいて喜んで実装したが、実は操作を途中でやめてもよかったらしい。そちらの解法は操作によって消す部分文字列を決めるdpで、遷移を高速化するために次の先頭となる文字で分類して値を持っておく。Dは二分探索で、ある番号以下の学校だけで全員が通えるかを判定するには多始点ダイクストラをすればよい。

Eはちょっと面白かった。先頭から二分探索して01が切り替わる境界を見つけるのを2回行い、axをそれぞれ求める。二分探索では、まず範囲として2べきを順に試し、次にその範囲内で通常の二分探索を行うので、都合4回、つまり最大4\log 10^9\gt 100くらいの質問回数が必要に見える。ここで、試す範囲はaに対応するものよりxに対応するもののほうが真に大きいため、xについてはaの値の続きから試していくことにすると、二分探索の回数が1回減って3\log 10^9\lt 100回くらいの質問回数で答えがわかるようになる。あとはb\lt 2xからbを求めて、最後にyを求める。baxから求まることに気づいておらず1WA。

ABC217-Gのゴルフの続きをする。PyPyでは負けてしまったので、Crystalを使ってみる。複数の値を出力するのがなかなか難しくて、どうやらjoinする必要がありそう。これだと出力の長さでPyPyに勝てなかったが、dp配列の埋め方を縦横逆にすると、毎ループの最後に1つずつ値を出力すればよいことになって、pで簡単に書けた。昨日入れたWSLにCrystalをインストールできたので手元でCEやREの様子を見ながらコーディングしていたのだが、AtCoder上のバージョン0.33.0と手元のバージョン1.1.1でもまたいくつか違いがあって大変だった。

また本を1冊読了。「かくりよの宿飯」4巻。前巻のラストシーンでとんでもないことになった主人公だが、なかなかたくましく生きている。さらに味方キャラがすぐ助けに駆けつけてくれて一安心。シリーズ最初のほうでは主人公は鬼神の大旦那に対してつんけんした態度をとっていたが、だんだん溶けていっているのもいい感じにニコニコできる。女主人公の視点で見ているので、溶けているという表現もちょっと違和感があるか。大旦那の良さがわかってきた、という感じ。

午前6時就寝。

09/05(日)

午後2時くらいに目を覚ます。またしばらく眠気の様子を伺いつつ布団でゴロゴロしていたが、やはり眠れないようだったので、今日も午後4時くらいに布団から出た。

昨日のABC217-Dは、Pythonのarrayとinsertを使ったコードでも通っていたが、C++コードよりは長かった。起きてみると自分のC++コードが縮められていて、どうにもこれ以上縮みそうにないので、改めて愚直にinsertするコードを考えてみる。Crystalでも同様のことができるのではないだろうかと思って書いてみると、通ってしまった。しかもコードがC++より短い。さらに何度か提出を繰り返して、111Bまで縮めた。

このように愚直なinsertが通ってしまうのはなぜだろうかと考えた。何か特殊な実装をしているわけではないだろうし、実はC++でも普通にinsertで通るのでは?と思って書いたら、見事に通ったので、特に不思議でもなんでもないようだ。ただPythonの通常のlistを使うと通らないので、型を制限することによるメモリ効率の向上が定数倍高速化に大きく寄与しているのだろうと思っている。

atcoder.jp

先週日曜日にLibrary Checkerに立てたissueがcloseされた。僕がissueの文面で提案していたケースがそのまま入ったらしい。実際に作業してくださった熨斗袋さんに感謝。

Add a test case to multipoint_evaluation by noshi91 · Pull Request #706 · yosupo06/library-checker-problems · GitHub

多点評価のハックケースをLibrary CheckerのGitHubにissueとして上げておいた。

週記(2021/08/23-2021/08/29) - kotatsugameの日記

午後6時からRECRUIT 日本橋ハーフマラソン 2021〜増刊号〜に参加した。

RECRUIT Nihonbashi Half Marathon 2021 (long) - AtCoder

まだ開催中のマラソンコンテストなので何も言えないが、一瞬だけ1位を取れた。

何も言えないのでこの間の時間は一気に飛ぶ(この間僕がコンテストに取り組んでいたということくらいは書いてもいいだろう)。午後11時半からCF #742 div.2に出た。

Dashboard - Codeforces Round #742 (Div. 2) - Codeforces

全完7位。

Aはよい。Bはaa+1かだと思っていたが、XORを合わせるために追加する要素がちょうどaの場合が困るらしい。サンプルにあって助かった。このような場合も、十分大きな2のべき乗を足すことでa+2要素で実現できる。Cは2つの繰り上がりを持つ桁dp。Dはまず各桁を10のべき乗に分解して、足りなければ小さいほうから10分の1にしていく。

Eは面倒。非減少部分列への分解を管理するのは、setに区間の両端を入れれば可能。求めるべき場合の数について、各要素に対してそれを終端とする非減少部分列がいくつあるかを数えると、それらの値はちょうどのこぎりの歯のような形のギザギザになる。つまり、傾きが1で定期的に1に戻るような値の列となる。数列の値の更新があると、このギザギザがある区間で一様に上がり下がりするだけの変化をするので、区間加算の遅延セグメント木で書ける。取得は当然区間和だが、一番前のギザギザは中途半端に取得されてしまうので、スタートを1にそろえなければならず、そこだけ区間を管理しているsetを見て補正する。僕は一番後ろも補正する必要があると思ってしまったが、その必要はなかった。

Fは謎。マークされたマスの周囲の空きマスは偶数個でなければならず、それらに1と4の数字が同じ回数だけ出現している必要がある。空きマスが2個の場合はその2マスに書かれる数字が異なることがわかるので、これを2部グラフの辺と見て奇閉路をチェックするような解き方をしたいが、空きマスが4マスの場合が難しい。特別扱いして、周りがある程度埋まったらうまいこと辺を張る、という感じで解けないかと思っていたが、そんなにうまくいかなそう。良い計算量の書き方が思いつかなかった。しばらく考えていると、ふと、空きマスが4マスの場合は斜めの位置関係のマスの組が全部互いに異なる数字になるように辺を張ってよさそうだと気付いた。そこが同じ数字になる必要があるケースは存在しないと思ったのだ。実装して投げたらpretestには通ったが、改めて考えてみると証明が回っていないことに気づいた。辺にはグリッド上でまっすぐな辺と曲がる辺があって、斜めの位置関係、つまりあるマスの上と左のような位置関係の2マスを結ぶときには曲がる辺を奇数回通らなければならない。しかしまっすぐな辺を通る回数の偶奇がわからないので、数字が同じか違うかはまだわからなかった。

Fはシステスに通ってハッピー。今回のセットは僕が本番で書いたコードより頭が良い解き方がいくつかあるようで、A問題はUとDを入れ替えているだけというのはともかく、Cで偶数桁と奇数桁を独立に考えたらただの足し算とみなせるのは感動した。

Fの証明が流れてきた。グリッドを外と内に分けて考えることで、上で述べたまっすぐな辺を通る回数が偶数であることがわかる。すると、斜めの位置関係の2マスが結ばれるときは合計奇数本の辺をたどっていることになるため、その2マスに書かれる数字は異なる。

今日の夕方縮めていたABC217-Dが1B縮んでいた。insertをまとめて書くことに執着していたが、<<演算子を使えば末尾への挿入が簡単に書けるので、分けることでさらに短くなるらしかった。

かなり昔の問題のゴルフをしようとした。フローを流すのでnetworkxを使おうと思ったのだが、入力形式が正しく守られていないようで、一度全部読んでsplitする書き方をしたらC++より長くなってしまった。ちょっと調べた感じでは、改行が正しいものよりも多いケースと少ないケースがそれぞれあるようなので、余計な空行があったり末尾に改行がなかったりしているのだろう。

Submission #25641840 - 九州大学プログラミングコンテスト2014

別に土日が休日であると意識していたわけではないが、結果的にこの2日間はインターンの業務を進めなかった。せっかくなので、もっとコードを書いて貪欲に稼いでいきたい。

週記(2021/08/23-2021/08/29)

08/23(月)

先週の日曜日は、週記を投稿してから布団に入り、少し本を読んで寝た。午前6時半だった。

午後1時起床。ワクチンの予診票を印刷して記入し、家を出る。まず大学生協でゼリー飲料をミールカードの1日分限度額いっぱい、6パック買った。ゼリー飲料はもともと好きだが、こういう機会でもないと食事としてたくさん買い込むのはためらわれるので、ちょっとワクワクした。地下鉄に乗って駅前まで出て、丸亀製麺で昼食を済ませる。今日も仙台駅にあるアンパンマンの石像を写真に収めた。

ほぼ予約通りの時間に接種会場に到着。今日は1回目のときよりも人が少ない気がするが、タイミングの問題だろうか。問診で、1回目の副反応で腕の痛みがひどかったことを訴えたら、氷嚢で冷やすくらいしかないと言われた。これは冷えピタではいけないらしい。氷嚢と冷えピタで患部を冷やすメカニズムが異なるというのは、あまり意識したことがなかった。

特に問題なく接種完了、15分経過観察して接種会場を去る。薬局に寄って冷えピタと解熱剤を買う。解熱剤がどこに売っているのかわからなくてしばらくウロウロしていたが、レジに立っている人が薬剤師さんだったらしく、話しかけるとレジの後ろにある薬棚からいろいろ紹介してくださった。先週の週記ではカロナールがいいのかもと書いていたが、置いていないようだし、薬剤師さんのおすすめを買うべきだろうと思って、結局イブクイック頭痛薬というものを買った。

まだ駅前で買い物を続ける。まずLOFTに入って洗面所にかけるための手拭きタオルを購入。前にもここで買ったことがあって、その時は1枚700円くらいのタオルしか見つからなかったのだが、今日は2枚組で1000円のタオルを発見した。次に本屋に行ってラノベを購入し、いよいよ帰宅した。

腕が痛くなることを見越して、帰ってきてすぐにシャワーを浴びた。その後、CF #739 div.3を解いた。

Dashboard - Codeforces Round #739 (Div. 3) - Codeforces

Aはよい。Bは-1を出力する場合分けが面倒だが、サンプルを合わせれば通る。Cも面倒なだけ。Dは適当に259まで調べたら通ったが、ちょうどそこまで調べればよいということに理論的な裏付けがあるらしい。つまり、答えが18桁以下となることが示せるようだ。Eは難しいと思ったが、まず文字が消える順番がわかり、各文字の出現場所を見てsとしてあり得るprefixを調べたら一意的に定まるのでOK。Fはよくわからない。出現した数字を10bitで持つ桁dpで解こうとしたがTLEしてしまった。まずF1は、10bitのうち高々2bitしか立っていないものだけ考えればよい。F2も同じ感じで計算量が削減できて、K\ge 7の場合は桁dpせず実際にインクリメントして探すことにしたら、639msで通った。想定解はprefixを固定してなんやかんやするらしい。

午後9時になって、ゲノコン2021に出た。AtCoderのトップページからリンクを辿れないので、かなり不便。

Genocon2021 ー DNA Sequence Analysis Challenge - AtCoder

今日はA問題だけが公開された。問題を一読してy/ATGC/TACG/だと思い込み提出、WA。実は答えをreverseしなければならなかったらしい。sedでreverseは難しいので、bashを使う。その場合はsedを呼び出すよりtr ATGC TACGのほうが短くなる。10分間の提出制限を悶々として待ち、2回目の提出でACした。21B。

布団に入って本を1冊読了。「世にも美しき数学者たちの日常」で、院試の面接後に図書館で借り出したもの。面白くはあったが、数学科の院に進むことを決めた今読むと、いろいろ思うところがあって素直に楽しめなかった。あとは、数学が苦手な人間が数学の面白さを知る、みたいなことに興味を持てないのも大きい。

なんとなく熱っぽいが、体温を測ると36.4度だった。しかし寒気がひどい。タオルケットしかないので、それに無理やりくるまるようにして就寝。午前0時だった。

08/24(火)

夜中から朝方にかけて何度か寝たり起きたりを繰り返していた。記録を残してある。

まず午前3時半ごろに頭痛と喉の渇きで起床。脱水症状で苦しむ人が多いらしいので、意識的に水分をたくさん摂る。熱を測ると38.3度だった。腕や足が熱を持っていて、寒気という意味では多少マシになっていた。次に午前5時半ごろ、また喉の渇きで起床。38.5度だった。頭を少し動かすと頭痛がひどいので、ゼリー飲料を食べて頭痛薬を服用。さらに冷えピタを貼った。さらに午前7時半ごろにも起床。頭痛は収まったかと思ったが、やはり頭を動かすとかなり痛む。今になってようやく少しばかり汗が出てきた。38.5度。

それからしばらくはスマホを触っていた。ワクチン1回目の時は、どんな体勢でも左腕が痛くてたまらなかったものだが、今回はそこまで痛くない。やはり1回目接種の直後にしこたまチュウニズムをやったのがマズかったのだろう。しばらくpixivで小説を漁ったりYouTubeを見たりしたあと、昼前にまた寝て、午後3時に目を覚ました。37.3度。

しばらく布団でゴロゴロした後、いよいよ起きることにする。食欲は全くないが、頭痛薬を服用するために食事はしなければならない。ゼリー飲料でもよかったが、多少元気があるので生協の冷凍弁当を温めた。熱を測ると37.5度だったので、まだ微熱がある。

7セメスターに取った全学教育の成績が出ていた。定理証明支援系を実装して提出した論理学はAA、数理統計学はAだった。まあいい感じじゃないだろうか。結局GPAがいつ使われるのかわからないまま院に進もうとしている。AとかAAを気にする必要は、今はもうないように思われる。

先週金曜日のyukicoderの問題を少しだけ解いた。なかなか難しめの回だったようで、3問だけ。

No.1650 Moving Coins - yukicoder

操作回数はすぐわかるが、実際に構築するのがちょっと面倒。ほかのコインに邪魔されずに目的地までたどり着けるコインを優先的に動かし、それが動いたことによって新たに目的地にたどり着けるようになったコインを操作待機キューに入れるという、bfsみたいなことをして解いた。解説は右に動くコインと左に動くコインの操作範囲が被らないことを示していて、非常に頭が良い。

No.1651 Removing Cards - yukicoder

実験すると、最後に残るカードというのはある程度一定らしい。しかもそのようなカードの種類はそれほど多くなさそう。なので、うまいこと最後に残るカードだけを前計算して、クエリには二分探索で答えるという方針が立つ。前計算はちょっと難しい。カードを0-indexedにするとX_{i+1}-\left\lfloor\frac{X_{i+1}}K\right\rfloor=X_i+1なるX_{i+1}が計算できればよくて、僕はX_{i+1}=X_i+1とした後条件を満たすまでX_{i+1}\leftarrow X_i+1+\left\lfloor\frac{X_{i+1}}K\right\rfloorと更新し続けたが、解説のようにO(1)で求めることもできるようだ。

No.1653 Squarefree - yukicoder

ちょっとTLでヒントを見てしまったかもしれない。区間篩を使って\sqrt[3]{R}までの素数で割り算した後、残ったものが平方数かをチェックすれば十分。

午後9時になって、ゲノコン2021にB問題が追加された。

Genocon2021 ー DNA Sequence Analysis Challenge - AtCoder

今日の問題はいつものdp。復元がかなり面倒。この問題のFAが3分を切っているのはかなり驚きであったが、どうやら事前に予想して問題を解いておいたタイプのFAらしい。

夜になって熱が下がり、頭痛も収まったように思える。寝たり起きたりを繰り返していたので眠気もあるはずだが、ともかく思ったより元気なので、CF #740 div.1に出ることにした。

Dashboard - Codeforces Round #740 (Div. 1, based on VK Cup 2021 - Final (Engine)) - Codeforces

4完86位で2886→2844(-42)。コンテスト中はpredictorが動いていなかった(プロフィールページへのアクセスが禁止されていたことが原因らしい)ためわからなかったが、自分のレートが上振れしすぎていて、生半可な順位を取るとすぐ落ちてしまうような位置にいたらしい。

Aはよい。先手2通りとAliceが自分のサーブをどれだけキープできたかを全部試すことができる。これが場合の数を求めさせる問題であっても面倒なだけだったろう。Bはメモリが制限されていて、空間O(n)が許されないのか?と不安になったが、調べたら余裕だった。最初に貰うdpを書いたらO(n\sqrt n)でかなり時間がかかっていた。これを高速化するのかと途方に暮れそうになったが、配るdpのほうも試してみたらO(n\log n)になっていてびっくりした。後者のまとめ方のほうがより多くの要素をまとめられるようだ。

Cは、偶数番目と奇数番目をそれぞれ独立にソートすることしかできないことがわかる。後ろから2番目の要素を正しいものにするとき、どうやっても最後尾の要素と一緒に動かしてくるしかないので、その2つの最初の位置関係2通りで場合分けしてみると、どちらもちょうど5手で達成可能なことがわかる。その操作を使って後ろから2つずつ決めていくとちょうど\frac{5(n-1)}2手で達成可能なので、想定解であることに確信を持った。毎回の操作で愚直にreverseしてよい制約なので実装も簡単。

Dは難しい。まず操作列の情報から、出来上がったソート済みの列の大小関係において\ge\gtがそれぞれどこに入るかを決められる。それがわかったら、対応して適当に値をいくらか引くことですべて\geに置き換えることができ、そのとき答えは重複組み合わせで計算できる。よって問題は最初のパート、操作列の情報を処理する部分だけになる。\gtの場所を管理することを考えると、「y-1以上の値をインクリメントする」「yを挿入する」ができればよい。この方針からbitsetなどを使って解くこともできるようだが、思いつかなかったため別の方法で解いた。

まず、新しく挿入する要素を、以前のインクリメントが適用されていた場合の数に置き換え、最後に一気にインクリメントする方法を考えた。しかしこれは置き換え先のちょうど良い値を確保できず失敗。次に、操作列を逆から見て、インクリメントされる先をありうるすべての値に対して管理することにした。こちらは、例えばy=3での更新を考えると、(0,1,2,3,4)\mapsto(0,1,2,3,4)だったのが(0,1,3,4,5)に置き換わり、次にy=1での更新を考えると(1,3,4,5,6)になる。つまり、列の途中を抜き去るような形で実現することができて、これは双方向連結リストで効率よく実装できる。どこを更新すればよいかは、消されていない数字を管理するBIT上の二分探索で判定できる。

実装はちょっとだけ面倒で、テストケースごとに初期化することを許されていないので、更新された部分だけ最後にロールバックする必要があった。

コンテスト後はラノベを読んでいた。途中でatgolferを確認したら、先週日曜日の技術室奥プロコンのA問題が縮められていた。どうやら数式を弄って場合分けするのではなくて答えをスタックに積んでRで持ってきたほうが短くなったらしい。そのコードには縮む余地が残っていたので、そこを縮めて取り返した。

CFのシステムテストを見届けてからベッドに移動し、それからもしばらくラノベを読み続けていた。残り100ページを切ったところで眠気に耐えられず就寝。午前6時だった。

08/25(水)

午後1時半ごろ起床。もうちょっと寝ようかどうしようかと2時間以上ゴロゴロしていたら眠気が消えてしまったので、ベッドから身を起こした。

昨日読んでいたラノベを読了。「辺境都市の育成者」4巻。カバー折り返しの著者コメントに「5巻出せたらいいなあ」と書いてあって、お前……打ち切られるのか?と焦ったが、後書きを読んだ感じでは普通に出そう。よかった。この作者の文章は読みづらいということを週記で何度も言及してきたわけだが、今巻でも読みづらさに新たな発見があった。とにかくセリフや描写の文章を最後まで書かないのだ。例えばそれは、視点人物の驚きを表現するためであったり、ここまで書けばわかるでしょう?という感じで省略したり。

……ということをここまで書いて、改めて本を確認したところ、別にそうでもないような気がする。体言止めが多い気もしたが、主に戦闘シーンだし疾走感の表現と解釈できるだろう。この独特の癖がある文章は、一体何に由来するんだろう。これまで文体に注目していたが、実は単純にセリフ回しが特徴的なだけかもしれない。どうであろうと、読みにくさをこらえて読むだけの面白さは十分ある。

「東方遺骸王」の更新が来ていた。最近は旧作1作目の東方靈異伝の話をやっていたのだが、一区切りついたらしい。東方古代スタートのオリ主ものは、原作が始まったら自機組に対応して動く必要が出てくるので、存分に無双できるのは原作前と、あとはクライマックスにありがちなオリジナル異変のみとなる。そういう意味では今作も例に漏れず、この章では主人公の雄(?)姿があまり見られなくてちょっと残念だった。

章題が「東方靈異伝」になっていた。ついに旧作突入らしい。感慨深い。

週記(2021/05/17-2021/-5/23) - kotatsugameの日記

東方遺骸王 - ハーメルン

GCJ Tシャツが届いた。間違えてSサイズを注文してしまっていたが、着てみると案外Mサイズより体に合っていた。やはりアメリカとのサイズ感の違いは大きい。これまでずっとコンテストTシャツはMサイズを注文していたが、そんな中で同じくらい体にフィットしていたものがあったのも確かで、この違いはどういうことだろう?と確かめてみたら、TCO RegionalのTシャツだったから、日本サイズのMだったということか。

GCJ Tシャツのサイズ表記はSM、MD、LGなどと書いてあって何のことかよくわからなかったため、胸囲と身長の対応など調べてSMにしておいたが、どうやらこれらはSMall、MeDium、LarGeの意味らしい。これまでは確かMサイズを注文していたので、間違えてしまったか?

週記(2021/05/24-2021/05/30) - kotatsugameの日記

学食に行って夕食を食べ、図書館で本を返却して帰宅。山の上で借りた本を下で返せるとは便利なものだ。本当はこの本は暇つぶしにちょっと借りただけで、返却してから下山するつもりだったのが、下でも返せるということを聞いてそのまま読み通すことを決意した、という背景があった。

今日もゲノコン2021。今日はC問題のマラソンが公開された。

Genocon2021 ー DNA Sequence Analysis Challenge - AtCoder

largeで正の点数を取るのが非常に難しかった。今のところようやく100点くらい取れて、もう限界。方針としては、まずすべての文字列を部分文字列として含むような文字列を作り、適当に文字を削除しつつ一致する文字数が最大になるようにうまいことあてはめてみている。1回の計算にかなり時間がかかるので全然試行回数が稼げず、最初のほうは一気に100文字くらい削除したりしつつ山登り法で頑張っている。一度に削除する文字数を増やしたことが、largeで正の点数を取れるようになった改善点だった。

マインスイーパを久しぶりにプレイしてみたが、トラックボールマウスだと難しい。細かい制御が簡単になるかと思っていたのだが、今のところ(慣れていないだけか)全然そんなことはないし、大きな移動はどうやっても難しくて散々。ボールに指を突き立てるのがよいとアドバイスをいただいたがこれもなかなかうまくいかない。

トラックボールの掃除ということも指摘されて、調べてみたら、実は掃除だけならドライバなど持ち出す必要はなく、ボールを裏から押し込むだけで取り外せたらしい!取り外してみると信じられないくらいのゴミが溜まっていて、取り除くと格段にボール操作がスムーズになったが、逆に転がりすぎてまた操作精度が悪くなってしまった気もする。まあ練習あるのみだろう。今はもうそこまでマインスイーパに対するモチベがなくなってしまったが……。

ラソン問題に対する別の方針を思いついたので試してみたが、全然ダメだった。各文字のインデックスを管理して適当に±1する焼き鈍し、文字列の表現では'-'を適当に挿入したり移動させたりして焼き鈍す方針だったが、文字が左右に散らばりすぎてしまった。

日記を書いた後、ふと大学生協で本を注文しようと思い立った。買っていない新刊はそれほどなく、今日は6冊注文した。週明けに届くだろう。

布団に入り、ラノベを読み始めた。適当なところで切り上げて寝るつもりだったが、週末は夜よりむしろ昼間にコンテストが集中しているようなので、このあたりで生活リズムを1周させておこうという気持ちになって、とりあえずそのままラノベを読み切った。

「英国カノジョは“らぶゆー”じゃなくてスキと言いたい」。あまり面白くなかった。最近似たような話が多すぎて設定に既視感があるとか、ヒロインの好意が1巻時点ですでに駄々洩れになっているとかは大きな問題ではなく、主人公の初恋相手が悪女で、かなり不穏な動きをしていたことが受け入れられなかったのが一番の原因。主人公は初恋相手をまだ好いていて、逆に手玉に取られておもちゃ扱いされそうになっているという展開で、1巻からする話ではないだろうと思ってしまった。

そのあと別のラノベに手を付けたが、眠気に耐え兼ね午前2時就寝。

08/26(木)

消えた。

08/27(金)

08/26 午後10時半くらいに目を覚ます。CFで謎のテストラウンドが生えていたので出ようかと思ったが、眠気が勝った。

次に目を覚ましたのは、午前2時くらいだった。スマホでTLを眺めていたら眠気が消え失せたので、午前5時くらいになって布団から身を起こし、パソコンの前に座って開いていた問題の考察をした。

Submission #25355266 - CODE FESTIVAL 2016 qual A

ちょっと前に橙diffを何問か解いたとき、一緒に考察も大体終わっていて、しかし実装する前に飽きてしまったらしく、未ACのままだった。当時の考察を思い出して解こうとしたが、実装している最中に全然詰め切れていなかったことに気づき、そこからさらに数日空いた。

2×2マスの条件は、マス目の縦横の差を見て一致していることと言い換えられる。すでに値がわかっているマスから、その差分に関する条件を取り出すと、矛盾していないなら適当に0埋めすることで全体のマスについての縦横の差が復元できて、差を累積的に足していって縦が最小になり、かつ横でも最小になるマスの値が非負かをチェックすればよいと考えていた。しかし実際にやってみると、復元できるのはある種の連結成分ごとに限られて、いくつかの連結成分が成立していても全体で成立しているとは言えないかもしれない。適当に手で試してみてよさそうだと感じ、提出すると、ACできた。

解説では、差を取った後適当に戻して、マス(i,j)の値がx_i+y_jとなるようなx,yを考察していた。これだと、値がわかっているマスから復元した情報を元に、ストレートにマスの最小値が非負であることを確かめられそうだ。

数学基礎論の単位が出ていた。AAだった。レポートを頑張った甲斐があった。4年ゼミは通年の講義として扱われるので、火曜日に出た2講義と合わせて今セメスターの成績が確定したことになった。しかし3つしか講義を取らなくてよいとは!2、3年生のときの頑張りがあって今、4年生でこんなに楽ができている。

またマインスイーパをしばらくプレイしていた。ボールに指を突き立てるとよいというアドバイスは、ボールを強く押さえながら操作するのが良いということだと考えているが、なかなかうまくいかない。細かい移動でもすぐ積み重なってボールから指がずれていってしまう。頻繁に指を置きなおすのもタイムに影響がありそうだ。ということでこのアドバイスはうまくいかず、今のところは諦めてポインタの移動速度を1段階下げることで対処している。

何度かプレイしていたらそこそこ良い記録が出たので、動画をキャプチャしてTwitterに上げた。中級で21.69秒。

昼過ぎ、外出する。学食で昼食を食べてゲームセンターに向かった。道中は信じられないくらい暑くて大変だった。いつもゲーセンに着くころにはマスクがしっとりしていて、そのままプレイしてさらに汗をかくものだから、かなり不快感がある。替えのマスクを用意しておくのも手だろう。

今日の成果は12の理論値が1譜面、13のAJが4譜面。おねがいダーリンの譜面が追加されたとき、当時実力が同じくらいだったFFがポンと理論値を出していたのを覚えていたのでプレイしてみたが、かなり精度を取りやすかった。といっても10回ちょっとプレイしている。途中FASTが少し出るようになったので判定を前にずらしてみたところ、なぜかさらにFASTが出るようになってびっくりした。結局この譜面は±0.0でプレイするのが一番らしい。

たいぺーと合流して夕食に向かおうとしていたら、インターン先から電話がかかってきた。ゲーセンの中だったので、折り返し電話しますと言って静かな場所を探したが、周りも繁華街でどうしようもなく、結局壁に向かって耳を塞ぎながら通話する羽目になった。何とか聞き取れたので安心。

夕食はガスト。魚介類は意識しないと全然食べないので、今日はネギトロ丼を注文した。帰りに本屋に寄ったが、水曜日に大学生協で新刊を注文してしまったので店頭では買えず、歯がゆい思いをした。

帰宅してyukicoder 311に参加した。

yukicoder contest 311 - yukicoder

ABDEFの5完。Gはともかく、Cが全然わからない。solvedが100を超えていて精神にダメージ。

Aはよい。Bは\frac{B(B+1)}2-\frac{A(A-1)}2=\frac{(B+A)(B-A+1)}2と式変形して、B-A+1の値で適当に場合分けする。するとB\le A+1であることがわかるので、適当に素数を前計算したあと全探索でよい。次にCを開いたが、わからなかったので、BのHard VersionであるFに移った。こちらは制約が1010くらいになっている。素数を列挙するのは不可能だが、知りたいのは個数だけであり、Library Checkerの素数カウントの制約が1011なので、そこからライブラリを盗んでくれば通る。

Dは素因数分解して適当に二項係数の計算をする。Eは(A-0E)^m=Oと見て、院試のことを思い出して固有値0だの広義固有空間だの考えそうになったが、サイズの制約105を見て冷静になった。非零要素のことを列から行への辺だと思うと、行列の積はパスの集まりと見ることができる。これでグラフの問題に落ちたので、あとはそこから最長パスを探せばよい。トポロジカルソートしながら計算できた。

Cの希望が見えないのでGを考えていたが、急激に眠たくなってしまった。コンテスト中だがさすがに耐えられない。午後11時前、ベッドに倒れ込むように就寝。

08/28(土)

何度か目を覚ましたり寝たりしていた。朝方目を覚ますということに慣れておらず、かなり現実感が希薄。結局午前11時くらいに起床した。しばらくコードゴルフをして、学食に行った。帰ってきてから午後2時までは、FHC Qualの問題を読んでいた。実装は後回しにして、午後2時から日本橋ハーフマラソン 2021に参加した。

RECRUIT 日本橋ハーフマラソン 2021 - AtCoder

まずAに1Bの解を提出してFAとshortestを取り、続いてBのゴルフをした。ちゃんと40x40マスに並べて出力しなければならないようで、Vimが最短となった。改めてマラソンに取り掛かる。

まずAにとりあえずの解を出した。\frac K 2以上で最小のものを\frac K 2未満で最大のものに足して1回オーバーフローを起こす。起こせないなら\frac K 2以上の要素を未満のほうに回して同じことをする。これを一通り行った後、\frac K 2以上の要素をそれぞれオーバーフローさせて、余った操作回数では適当に2倍してみたりする。これで86216点だったが、周りと比べてかなり低いので、見切りをつけてBに移った。

Bは、性能が高い椅子だけを抜き出してパワーを1増やす焼きなましをした。40個抜き出すと156656点だったが、全体のちょうど半分、800個の椅子を抜き出すと191210点と急激に伸びた。実はこの時、過去のAHCで目にした解法を真似して椅子のパワーを0に戻す更新もたまに行っていたが、後に無駄であったことが分かった。実際、椅子のパワーを0に戻す更新の確率を引き下げた提出は194644点と少し伸びていた。

そのあとしばらくパラメータを変えて投げ続けていたが、全然変わらない。と、ふと、焼きなましの更新処理に間違いがあることに気づいた。今見ている椅子の動作音の範囲にほかの椅子が入っていたらその椅子のパワーは0にしなければならないが、ほかの椅子の動作音の範囲に今見ている椅子が入った場合は、その椅子のパワーを下げるにしても0にする必要はない。ここを直したら一気に209130点と1桁順位に入った。さらに、出力する直前に空いているマスがあった場合はそこの椅子を動作させることにしたら、209413点になった。

これまでTL目いっぱい焼きなましをしていたが、時間を短くしてもスコアにはほとんど影響がないようだ。なので、同じ焼きなましを15回行い、最良の解を出力するようにした。これで211058点となり、B問題の最終結果となった。

ここまででコンテスト時間は残り40分くらいであった。A問題でまともな点数を取れれば景品がもらえる可能性があるので、改めて挑戦してみる。値の大きいほうから順に相方を探して小さくしてみたが、全然スコアが出ない。ビジュアライザを見ると謎の挙動をしている。コードを読み直してみると、大量のバグが見つかった。不等号の向きが違うので値を大きくしてしまっていたり、更新前の値をそのまま参照しているため意図しない足し算をしたり。ここを直すとそれなりにまともなスコアが出た。相方を探す処理のループを増やし、そちらでは自分を2倍して試してみるという処理を追加して115146点。残り時間がほとんどないが、自分を4倍する処理も無理やり書ききってギリギリで提出したら、122478点になった。

終結果はA問題267位、B問題8位で積の順位は37位。景品は上位40名までは必ずもらえるので、何とか滑りこめたようだ。

コンテスト後に少しTLを眺めていたが、A問題は\frac K 2で分けるのは良くて、そのあと一旦0Kに少しずつ寄せてから、改めて0に寄せるのが良いらしい。そうでなくても、みんなある程度アルゴリズムで押していて、試行回数がどうのという問題ではなかったようだ。B問題は、動作させる椅子の集合を決めると設定すべきパワーがわかるので、動作させる椅子の集合を焼きなますと良かったようだ。これは非常に面白い。できるだけシンプルで根本的なものを焼きなますのが一般に良いのだろうか。

今日はこの後何もコンテストがない。電車で街に出て碧黴さんと食事した。土曜日の夜、この時間に出歩くのはなかなか新鮮な気持ち。赤達成のお祝いに日本酒を下さるという話を前からしていて、ついにそれを受け取った。

帰り道で別れた。ゲーセンに行こうとしたが、お腹がいっぱいなのでしばらくブックオフで休んでいこう、と久しぶりに入店した。棚を見ていると、文庫本でシリーズ11冊全部そろっているものを発見し、思わず買ってしまった。重い荷物を抱えてブックオフを出て、ゲーセンに向かった。今日は特に成果なし、素手だったのでスライダーが滑らなくて大変だった。2時間くらいプレイして帰宅。

atgolferに流れてきた更新ですごいものがあった。2数のbitwise andとしてありうる最大値を求めるのは上位桁から決めていけばよかったが、これは区間の左端を0、右端を2^{31}にした二分探索で実現できる。挙動を思い浮かべれば確かにという感じだが、これに気付くのはすさまじいとしか言いようがない。

Submission #25382467 - 技術室奥プログラミングコンテスト#6 Day1

Facebook Hacker Cup - 2021 - Qualification Round

今朝読んでいたFHC Qualの問題を実装する。提出しようとしたら、今年から入力ファイルがパスワード付きzipで渡されるようになったらしく、かなり困惑。自分のパソコンに7-zipが入っていたので事なきを得たが、エクスプローラーでできないことを要求されるとびっくりしてしまう。取り合えずaABcを解いた。このことは順位表からわかる情報だが、問題の内容に関する言及が許されていたかどうか記憶にないし、この日記が公開される時点でまだコンテストは終わっていないので、特に何も書けない。

Cを考えていたらうっかり意識を飛ばしてしまったので、素直に布団に入って就寝。午前1時だった。

08/29(日)

午前7時半起床。かなりまともな生活リズムになってしまい、夜中のコンテストに不安がある。なのでもう少し寝ておこうと布団でゴロゴロしていたが、全然眠れなかった。YouTubeを見たりなろうを読んだりしていた。

昼前になって起きだして、食事したりコードゴルフしたりした後、午後1時から技術室奥プログラミングコンテスト#6 Day2に出た。

技術室奥プログラミングコンテスト#6 Day2 - AtCoder

ABCDFHjKの4300点で11位。

Aはかなり迷走して、小さなケースを実験してようやく気付いた。挿入dpのようなことを考えれば自明。4分ちょっとかけて出したdc 15Bは、コンテスト後に見たところ、何とか最短を取れていた。Bは文字列の先頭に'A'をつけて、隣接する文字が異なるかどうかを管理することにした。適当に操作を言い換えると、前から貪欲に揃えるのが楽に書ける。Cは実験して規則性に気付いた。コードゴルフ的には、N=4のときの解としてサンプルにある[2,3,2,1]ではなく[3,1,3,1]を使うと、繰り返しになるのでちょっと短く書ける。Dは01を繰り返してYesが返ってくる文字列を作成し、後ろから削っていく。N=1のときに空文字列をクエリとして投げてしまい、WAを何回か食らった。

Eが解けなかったのでFに移る。FはD_1との偶奇の違いを見て、もし異なっていた場合はそれ同士でうまいこと構成しておく。最後に辺が規定量に達するまで重み最大の辺を追加する処理が面倒だった。1点、D_1=0のときに奇数長のパスを求められるとうまく構築できないケースがあって、それにも引っかかった。

次にKがたくさん解かれていたのでそちらに移った。二項係数をバラしてみると、前の答えに何をかければよいかがわかる。具体的には\prod(A_i+x)x^Mで割った形をしている。割り算のほうは適当に計算することにして分子を考えると、多項式を計算して多点評価すれば求める値が得られる。1次式の積を高速に計算する方法がわからず、logでも取ってみようかといろいろ調べていると、分割統治法で計算すればよいという言及を見つけたので、セグメント木に乗せてall_prodした。多点評価はうしさんのライブラリを盗んできたが、多項式が0と等しくなってしまった場合に配列外参照をしてしまうバグがあってREとなり、大変だった。適当に試したケースが当たらなかったらバグの原因は一生わからなかっただろう。

次にJ。500点は一瞬だが800点は全然わからない。多分速いんじゃないかと思って書いたコードは普通にTLEを食らってしまったので、部分点のまま放置。順位表を見る感じ解けそうな問題が全然ないが、気力を奮い立たせて問題を読んでいると、Hが解けた。操作をまとめると、隣接しない駒を選んでひっくり返したと見ることができて、値の最大化も含めてセグメント木に乗る。

コードゴルフはCをRubyで、DをPerlで。DのN=1のケースで空文字列をクエリにしない場合分けが難しい。

多点評価のハックケースをLibrary CheckerのGitHubにissueとして上げておいた。

github.com

またしばらくFHC Qual Cを考えていたが、結局解けずじまい。諦めることにした。

午後9時からABC216に出た。

AtCoder Beginner Contest 216 - AtCoder

7完。Eで詰まってペナが大変なことになったほか、Hが何一つわからなくてかなり衝撃的。

Aからやや面倒。最初どう実装したものか迷って、とりあえずsedで出した。BはRaku。CからC++。DはBFSっぽく操作可能なボールを管理する。Eは二分探索して落ち続けていたが、原因は、ちょうどボーダーとなるような値も使いながら計算していたからだった。ボーダーとなる値は最後にあまりとして使わなければならない。コンテスト時は結局stackを使い、値が大きいものから順にまとめて操作するように書き直した。FはAをソートして\maxとなるインデックスを固定すると、残りは部分和問題になる。Gはrでソートして大きいほうにできる限り詰めつつ構築したいが、これはsetで使っていないインデックスを管理すれば可能。

Gは牛ゲーらしい。なるほどという感じ。Hは解説を読んでいないが、LGV公式を使うらしい。それがわかっていてもまだACまでは遠い。

コードゴルフ。Aはdcになった。BはVimらしい。Cもdcだが、文字列を出力する代わりに12進数で適切な数字を出力するというのはなるほどなあ、という感じ。Dはakouryyさんのコードがとても上手くて唸らされた。各列を直接持っておいて、先頭要素を取りだしてみて1回目の出現だったら残りの列を保管、2回目だったら保管しておいた列と一緒に次に調べる列のqueueにpushする。縮む余地を発見したので縮めた。

Submission #25454127 - AtCoder Beginner Contest 216

EはRubyのコードをVimで書くやつ。似たようなコード片が何度か出てくるので、変なところで入力を中断して、直前に挿入モードで入力した文字列を再度入力するコマンドを多用すると短いらしい。FはとりあえずRuby

今朝早く起きてしまったので眠気がちょっと怖いが、CF combinedに出た。

Dashboard - Deltix Round, Summer 2021 (open for everyone, rated, Div. 1 + Div. 2) - Codeforces

6完97位、2844→2823(-21)。Fにかなり時間をかけてしまった。

Aはよい。Bはどちらかのパリティの要素だけ抜き出して前から順に並べ、元の位置との距離の和を計算する。Cはかなり迷走したが、括弧を±1と読み替えて累積和を計算したとき、谷として複数回出る値「だけ」をstackで管理するとそれなりに簡単に書けた。そこだけが何回も答えにカウントされる可能性があって、それ以外は累積和の変化を見るだけでわかる。Dは3要素のbitwise and/or 6通りを書き並べてみると、元の要素3つが一意的に定まることがわかる。これを配列の先頭3要素で行い、あとはそれとほかの要素のbitwise and/orをそれぞれ計算することで、すべての値を復元することができる。

Eは数列aのみに対する操作に言い換えると、±1で均せばよいとわかる。これまた括弧列を思い出すようなチェックを行えばよい。具体的には、累積和が区間の左端と右端で一致していることと、累積和の区間minが左端の値未満になっていないこと。操作回数の最少は、括弧列でいえば最もネストした括弧の数、累積和においては区間maxから左端の値を引いたものであった。Fは「ある部分集合が強連結成分となる」ようなdpを考えて除原理。3^Nのループ内部で、固定した強連結成分とそれ以外の頂点の間の辺を向き付けて係数を計算するところがO(N^2)かかるが、必要なインデックスだけ先に抜き出しておいたら1secを切った。

今日は合計で10時間近くコンテストに出ていたらしい。夜中、眠気に耐えつつ日記を書いていた。来週からいよいよインターンだ。日記に書いてよいことと書いてはいけないことをしっかり区別するようにしたい。

週記(2021/08/16-2021/08/22)

08/16(月)

先週の週記を投稿してから寝るまでの話。と言っても、先週の週記の最後で宣言したように、今日は夕方くらいまで起きておいて生活リズムを無理やり整えるつもりであるから、これから寝るまでが月曜日の予定だ。普段ならこんな時は前の日の欄に全部書いて、代わりに1日ぶんの日記が消滅するのだが、たまたま週の変わり目に被ったため、このように日曜日と月曜日に分割して書いている。

また院試の過去問を解き進めていた。少し年代を遡ると、選択問題で選ぼうと思っていた分野の問題が解けないことが多くなってきたため、そのような場合でもなんとか点数を稼げるようにと分野を絞らず解けそうなものにとりあえず手を出してみる。流石に8問全部難しいということはなくて、自分でも解けるような問題が何とか少しずつ見つけられた。

そうこうしているうちに午後4時を回り、ちょっと椅子の上で意識を飛ばしてしまったので、このあたりで切り上げて布団に移動。午後5時半就寝。

08/17(火)

起きたらちょうど日付が変わったころだった。まだもうひと眠りしておきたいとは思っていたが、うっかりスマホを触り始めてしまう。YouTubeを見たりTLを眺めたりして布団の上でゴロゴロしていたら、すぐに時間が過ぎ去ってしまった。途中院試の解けていない問題を考えて解けたりもしたが、本番はそのような悠長なことはできない。構築問題なので、すぐに思いつかないならちゃんと諦める必要がある。

外が明るくなってきたので、ちゃんと意識的に睡眠する。午前5時前くらいに入眠して、今度は午前8時半に起床。いいんじゃないだろうか。2度目の睡眠は3時間ちょっとなのでかなり眠気はあるものの、足したらそれなりの睡眠時間になるので、これで起きることとする。

朝のうちに、夜中思いついた解答を実際に書いてみることにした。問題はこうだ:\{0,1\}の有限列からなる計算可能な無限列\{f_n\}_{n=0}^{\infty}であって\forall n.{\rm len}(f_n)\gt nを満たすもののうち、性質(\ast)を満たすどんな関数g:\mathbb{Z}_{\ge 0}\rightarrow\{0,1\}も計算可能とならないものを1つ挙げよ。ここで(*):\forall n\in\mathbb{Z}_{\ge 0}.\exists f_m.n\lt {\rm len}(f_m)\land(\forall i\le n.g(i)=f_m(i))

実際の問題文はもっと細かいのだが、だいたいこんな感じの問題だった。令和3年の数学基礎論分野の問題である。

自分の構築は、有限長のプログラム全体を\{\varphi_n\}_{n=0}^\inftyとした上で、{\rm len}(f_n)=n+1かつ

\displaystyle f_n(i)=\begin{cases}
1\quad(\varphi_i(\varphi_i)の計算がnステップ以下で終了する)\\
0\quad(otherwise)
\end{cases}

とするもの。これは実際にnステップ実行してみればよいので計算可能で、しかしg(i)\varphi_i(\varphi_i)の計算が停止するかどうかを判定しないと決められないので、計算不可能になりそう。

実際は何かの停止性判定問題に帰着するのではなく、もっと直接的に計算不可能性が示せる。つまり、gが計算可能だとしたら、そのプログラムを使って「Q(\varphi)が停止する\Leftrightarrow\varphi(\varphi)が停止しない」という条件を満たすプログラムQが作れて、ここでQ(Q)の停止性を考えると矛盾。この証明はくれちーさんに教えてもらった。

多分解けているだろう。計算可能な無限列の定義もちょっと怪しかったが、集合として計算可能であることは言えるはず。ある\{0,1\}の有限列(これも問題文ではちゃんと自然数エンコードされている)が与えられたとき、それがいずれかのf_nと一致するかを判定するには、列の長さから番号nを特定して、実際にf_nを計算すればよい。

解けたら午前10時を回っていた。部屋のゴミをまとめて出し、大学生協に向かう。お盆休みは昨日までで、今日から営業を再開しているはず。

午前11時に生協に到着したが、学食は午前11時半からだったので、その間に床屋で髪の毛を切ることにした。今日の担当者もいつだかと一緒で、すべての工程が終わった後に気に入らない部分があったのかはさみでチョキチョキしだして、勘弁してくれという気持ちになった。シャンプーの時に全然泡立たなかったが、これは自分の頭髪が汚れていたということだろう。直近でシャワーを浴びたのは月曜日の午前7時半くらいだったようだ。24時間以上経過しているため、来る前にもう一度シャワーを浴びてくればよかった。

学食で食事して帰宅。学食で集団で喋っている人間は叩き出したほうがいいんじゃないかと思った。しばらくYouTubeを見たりコードゴルフをしたりして過ごした後、午後3時から本番前最後の院試ゼミ。

今日も良かった。みんなが何を言っているかも問題なく理解できた。あとは過去問で出現していない概念が出題されないことを願うばかり。急に単語や定理のステートメントを問われると、場合によっては爆死しかねない、と思っている。対称群の部分群であって特定の位数を持つものを数え上げる問題があって、自分は対称群にも苦手意識があったのでまともに考察していなかったが、初手で数列の特徴に帰着しさえすれば、後は競プロで培った数え上げ力でぶん殴れる問題だったようで、面白かった。

午後7時までみっちりとゼミをしていた。これから本番までは共通問題の見直しをしようと思う。院試説明会で、先輩から共通問題を固めるとよい(と思う)と話をされたからだ。

途中院試の問題を解きつつ、ラノベを1冊読んだ。「鳩子さんとラブコメ」3巻。2巻までは特に興味がないということを話していたが、3巻は結構面白かった。だんだん主人公の特異性が明らかになってきて見る目が変わったことが影響している。文中に顔文字を挿入したり、文字のサイズやフォントを細かく変えてセリフの口調や盛り上がりを表現するのは、一昔前のラノベの技法という感じがして面白い。昔どこかで、文を稲妻の形に並べたり、AAでキャラクターの席順を示したりしたラノベが話題になっているのを見た覚えがあるが、そのような表現は最近のラノベでは全く見ない。

せっかく整えたはずの生活リズムだが、もうすでに日付が変わってしまった。せめて明後日の面接まで何とか保ちたい。日記を書いて就寝。午前2時半だった。

08/18(水)

午前9時起床。あまりにも理想的な生活リズムを獲得してしまった。

早起きすると、1日という時間の信じられないくらいの長さを体感する。これだけ長いなら、まだ院試の勉強始めなくても大丈夫かな……?ということで、昨日から始まっていたTCB39の問題を解いた。

https://techful-programming.com/user/event/2214

常のように、この週記が公開されるときには終了しているだろうから、ここに結果と各問題の所感を書いておく。結果はだいたい55分で理論値-12ptだった。7問目でWAを出したのが痛すぎる。

1、2、3問目はよい。サンプルコードが文字列の入力を読んでくれるので、それを流用できるのもいい感じ。4問目は面倒なだけ。5問目はやるだけ。6問目は先頭から貪欲に取ってもよい。7問目は、異なる文字から構成されるグループを作ってその中で完全グラフにするのがよい。グループ分けは出現回数を記録しておく。最初、各文字から出せる辺の本数を考えて2で割るということをしていたが、大間違い。そもそも奇数を2出割る可能性があるコードだったのだから、ちゃんとチェックすればよかった。8問目は1つのペアで操作する場合と2つのペアで操作する場合に分けて丁寧に場合分け。9問目は自明。

10問目は難しい。まず、ある連続部分列が操作によって空文字列にできる条件を考える。しばらく悩んでいたが、ふとインデックスの偶奇で±1を割り振り、文字ごとに足して総和がどちらも0になることが必要十分条件であることに気づいた。ド典型っぽいので、どこかで見たのを何とか思い出せたのだろう。あとは部分列を重複がないように数え上げればよく、dpの遷移は追加できる(間を空文字列にできる)文字のうちそれぞれ最も近くにあるものに飛ばせばよい。最も近いものだけ考えてよいことも、先の必要十分条件から言える。もらうdpで書いた。

院試の問題を解く。今日は本番前日ということで、以前に院試ゼミで他の人が解いていた去年の共通問題の解答を再現してみた。ところが思ったより難しい。2時間粘って、結局院試ゼミのSlackに上がっていた当時の解答を見てしまった。

学食に行って昼食。その後購買で買い物をしたが、パンが大量に割り引かれていた。昨日はお盆明け初日ということで客入りが少なかったのだろう。見れば今日のパンも、昼過ぎであるにも関わらずかなり残っている。このように大学生協の売り上げ不振を目の当たりにすると非常につらい気持ちになる。頼むから潰れないでほしい。

院試が終わったらすぐ2回目のワクチン接種で、以降8月いっぱい副反応で身動きが取れなくなる可能性がある。CHUNITHMの現行イベントのうち1つが09/01で終了してしまうようなので、今のうちに走り切っておくのが良いようだ。ということで、今日はこれからゲーセンに行くことにした。

午後2時過ぎにゲーセンに着いて、午後9時までプレイ。そこそこで切り上げるつもりだったのに思ったより熱が入り、結果この時間までプレイしてしまった。今日は理論値を狙っていて、見事新規に4譜面で達成した。他にも「アポカリプスに反逆の焔を焚べろ」のSSSも達成した。正直なぜ出たのかよくわかっていない。クソ速い片手2連打とそのあとの鍵盤がたまたまうまくいったようだが、再現性が一切ない。

理論値、多少は譜面を選んだものの、それでも頑張ったら案外出るものらしい。今日の教訓としては「目で押さずに曲をよく聞く」「Fastが多いので判定を少しいじる」「集中が切れたら赤が出る」くらい。

夕食は立ち食い蕎麦屋。ざるうどんを頼んだらうどんのコシが強すぎて顎が負けていた。二度と頼まないようにしたい。ドンキで明日の朝ご飯を買って帰宅。

数学基礎論特選のClassroomが更新されていて、提出されたレポートの出来が良かった解答を集めたPDFがアップロードされていた。僕のレポートも2問ばかり選出されたようで、誇らしい気持ちになった。一方僕が匙を投げた問題も実際に解いてきた人がいるのを知り、差を感じることにもなった。以前の週記で言及した論理パズルとモデルについての話だが、これに関しても実際にモデルを用意して考察している解答があった。

与えられた論理パズルについて「共有知識」の定義を参考にしつつ論じよという問題があった。何か適当なモデルを用意するのかと思ったがどういう感じになるかちっともわからない

週記(2021/08/02-2021/08/08) - kotatsugameの日記

家に帰ったら院試の勉強をしようと思っていたが、コードゴルフしていたら日付が変わってしまった。もうジタバタせずに寝たほうがよさそう。ということで午前1時に布団に入り、冴える目を何とかなだめすかして就寝。

08/19(木)

午前6時くらいに目を覚ました。予定ではあと1時間くらい寝ているはずだったのに、全然二度寝できる気がしない。しばらく布団でスマホを使って院試の過去問を眺めていたが、諦めて身を起こした。

食事をしたり体温を測ったり(36.5度)院試ゼミのSlackで過去問の解答を眺めたりして朝の時間を過ごし、午前8時過ぎに家を出た。先頃までとは違い今日は非常に天気が良く、青空を見ているとなんだか元気が出てきた。今日は地下鉄で山に登る。試験会場についてからは、1年以上ぶりに対面するクラスメイト達と喋っていた。

試験は午前9時半から正午までの共通問題、午後1時半から午後3時半までの選択問題、午後4時から午後5時までの英語の3回。試験後の解答用紙回収・チェックの時間が長いのは大事な試験の常だろうが、そのせいで英語の試験が10分繰り下げになったりもした。そういう合間の時間は大学入試だと何もできないが、大学院にもなるとそこそこ緩くなるので、僕は持ってきたラノベを読んで無聊を慰めていた。久しぶりに長時間シャーペンを握ってガリガリ書いたところ、10年来の付き合いであったペンだこが消えかけていることに気づき、かなり感傷的になった。

終了後は数学科の人十数人で別の建物まで行き、そこの黒板で出題された問題に関して議論を交わした。感染症対策的にはあまり褒められた行動ではないのだろうが、それでも久しぶりに持てたこういう時間は信じられないほど楽しかった。結局5時間くらい喋って帰宅。実のところ真面目に議論していたのは最初の3時間くらいな気もする。

明日の面接のために、今日の試験に対する自分の所感をまとめておこう合格体験記に移した。

kotatsugame.hatenablog.com

総評して、別に易化傾向でもなんでもなかったが、出題難易度に助けられた感じこそあるもののそれなりに戦えているようなので、試験の結果には満足している。

帰宅してシャワーを浴び、洗濯機を回し、ラノベの新刊チェックをし、日記を書いて午前4時に就寝。明日は面接だが、午後からなので心に余裕がある。

08/20(金)

午前10時半に起床。面接で必ず聞かれるらしい「好きな定理」について考えながらゆっくり朝食を摂って、昼前に大学に行く。2-SATが多項式時間で解けることについて喋ろうと決めた。

集合が午後の人々と合流し始めた。分野によってスーツが推奨されるところとそうでないところが分かれるという話は聞いていたが、実際に集まってみてみんながスーツを着用しているのを目の当たりにすると、Tシャツを着てきた自分としてはちょっぴり肩身が狭い。

面接の待ち時間で、最近読んでいたラノベを最後まで読み切った。「鳩子さんとラブコメ」4巻。シリーズ完結である。主人公のたくらみに関する才能が明らかになって、3巻から何となく面白く感じられてきたが、そのままシュッと終わってしまった。

面接自体は10分程度で終了。細かい話はこれも合格体験記に書いておいた。1人、たくさん質問してくださる先生がいて、これは自分に興味を持っていると解釈していいのだろうか……?ドキドキした。

面接が終わってからは図書館に移動し、午後5時の合格発表を待つ。ちょっとだけ昨日の問題について話していたが、気が抜けてあまり身が入らない。合間に読む別の本を持ってきていないので図書館から1冊借り出したが、すぐに別の人がSwitchを持ってきたので、それからはスマブラで対戦していた。僕はWiiスマブラをそれなりにプレイしていて、いつもピットを使っていたので、今日もそれを選択。上必殺技の自由度がかなり制限されていてびっくりした。Switchのコントローラーを横持ちしてゲームするのはかなり無理があるということも感じた。

午後5時になったので掲示板を見に行く。何気に掲示板で合格発表を見るのは人生初かもしれない。高校受験の時は寝ていたら親が見に行ってくれた覚えがある。大学受験の合格・不合格発表はネットで見た。数学棟の前につくと、ぽつねんと掲示物が立っていて、ヌルっと合格していた。一安心。

3人で打ち上げと称して食事しに行く。駅前の商店街を歩いて牛タンの店を探したが、どれもちょっとお高いことに気づいてしまったので、ファミレスに行くことにした。途中もう1人参加することになって、待ち時間にゲーセンに入り、僕がCHUNITHMをプレイしているのを見せるやつをした。音ゲーだから音楽が聞こえなければ話にならないのに、プレイヤー以外には筐体の音があまり聞こえない(聞こえたら逆に問題か)ので、周りで見ていてどうなのかはよくわからない。譜面が流れる速度が速すぎてよくわからないというような感想を貰った。

ガストで食事。ポテトが思ったより多かった。入店した時間が遅かったので、すぐ閉店時間になってしまい、慌てて店を出る。そこからはもう帰宅する流れで、僕は途中で別れて再度ゲーセンに入った。

改めてチュウニズムをプレイする。今日は「星色夜空」の理論値を狙ってみたが、軍手をしていないのが影響したのか、今日は赤JがかなりLATEに振れていた。またエアーやエアー後の同時押しで死ぬほど赤を出し、非常に嫌な気持ちになった。必死に頑張って50回くらいプレイし、ようやく出せた。

閉店直前のラスクレで4曲チケットを使ったら、終わり際に店員さんに帰る準備をしてくれというようなことを言われてしまった。まだ1人ほかに残っていると思っていたが、どうやら店側の人間だったらしい。慌ててゲーセンを出て帰宅した。

内定が出てから院試終了まで待ってもらっていたインターン先に、無事合格したことをメールした。当時は本当に院試勉強で忙しくなるのか疑問に思っていたが、結局かなり頑張ったので、インターン開始を待ってもらったのは非常にありがたいことであった。

このインターンに内定が出た。ありがたい限り。手続きはすぐに行うが、実際に働き始めるのは僕の院試が終了してから、つまり9月くらいからになるようだ。

週記(2021/06/07-2021/06/13) - kotatsugameの日記

午前1時半くらいに急激に眠くなったので、慌てて布団に倒れこんだ。そのまま就寝。

08/21(土)

午前11時過ぎ位に目を覚ます。なんとなく眠気を感じたため二度寝しようと思い、ずっと布団でゴロゴロしていたが、全然眠れないので起きることにした。

生協の弁当配達の注文をしてからABCまではずっと合格体験記を書いていた。途中で生協の弁当が配達された。今日の分を注文したことをすっかり忘れていてパックご飯を温めたところだったので、かなりびっくりしたが、二度寝していて受け取れないというようなことにならなくてよかった。

午後9時からABC215。

AtCoder Beginner Contest 215 - AtCoder

7完。Hも解けそうだったが、2WAが取れなかった。なかなか全完できない。

Aはよい。Bは何か簡単な方法がありそうだが、すぐには思いつけなかったので2進数表示した桁数を見た。Cは順列を全列挙。Dはエラトステネスの篩と同時に素因数を前計算しておいて素因数分解し、答えの候補を全探索してこれも素因数分解でチェックした。Eはちょっと面倒なbitDP。状態が2^10\times 10\times Nくらいあってかなりびっくりした。Fはx座標でソートしておくと尺取り法のようにして二分探索の判定が線形時間で行える。

Gはdp配列を多項式だと思いながら計算すると(1+x)のべき乗いくつかの和を計算する問題に落ちる。これは(1+x)を掛けつつ0次の項をいじることである程度まとめて計算できて、O(N^2)に定数倍2分の1がついたくらいになる。900msで通った。HはHallの結婚定理を考えると、キャベツの集合Sに対して「Sに含まれるキャベツの個数」引く「Sからしか出荷できない注文の個数」を計算して、これが負になるようなSを作れればよい。この計算自体はゼータ変換で行えるが、場合の数を求めるのが難しく、結局通せなかった。

コードゴルフをする。A問題は通した後も別の問題の合間を縫ってテストケースハックをしており、コンテスト中に現在の最短である19Bのコードが完成していた。B問題は解説を読んで整数のmsbを答えるだけだったことに気づき、慌ててRakuで取っておいた。CはRakuが短かったが、RubyVimから呼び出すコードに負けた。しかし何とか取り返すことに成功。空白を含めて9文字で順列を生成しても答えは変わらないが、実行時間はかなりギリギリだった。DはPerl。Eは手つかずで、FはRubyのbsearch。

D問題の素因数分解は、O(\sqrt A)で行っても間に合うらしい。Eのdpはこの状態数107が想定解でびっくり。

Hの解説を読んで、自分の間違いに気づいた。上のようにキャベツの集合Sに対してf(S)を「Sに含まれるキャベツの個数」引く「Sからしか出荷できない注文の個数」と定義したとき、{\rm argmin}f(S)には複数の集合が含まれ得る。僕は、キャベツの集合TUについてf(T\cup U)f(T)以下またはf(U)以下になると考え、このことから{\rm argmin}f(S)のうち包含関係について極大なものたちは互いに交差せず、よってそれぞれ考えればよいだろうと思っていたが、f(T\cup U)の評価が違っていた。この場合、数え上げのためにはさらに何度かゼータ変換とメビウス変換を行う必要があって、大変に面倒だったので、気づけてもコンテスト中に通せたかは微妙だろう。

Hのupsolveをした後は合格体験記を書く作業に戻り、朝方になって投稿した。

kotatsugame.hatenablog.com

午前6時就寝。

08/22(日)

午後0時半に目を覚ます。食事して午後1時から技術室奥プログラミングコンテスト#6 Day1に出た。

技術室奥プログラミングコンテスト#6 Day1 - AtCoder

Aはカス。適当に引き算すればいいだろうと思っていたが、念のためサンプル2も確認したら微妙に違う。そこで問題文に戻ってよく読んでみると、何やら怪しげなことが書いてある。実際トップページから過去のコンテストの日程を確認すると、2017年だけ開催されていなかったので、それと2015年、2016年を場合分けしてAC。カス。聞いた話によるとサンプル2は最初置かれていなかったらしい。ありえん。お誕生日コンテストだったのならお誕生日コンテストと書いておいてほしい。

Bは色が十分多いので適当にやってよい。Cは平均値だと誤読して1WA。Dは累積和をソート、mod取り忘れとソート範囲ミスで2WA。Eは最後に答えを2倍するところでオーバーフローして1WA。このあたり、焦っているのに出すコードが軒並み落ちてしまってかなり辛かった。Fは適当にdp。Gは謎の条件を使ってLISの更新をセグ木の範囲取得2回で行う。Hは冷静になるとソートして貪欲に足すのを2回行うだけでよい。オーバーフローで1WA。

Iが解けなかったのでいったん飛ばす。Jは負辺ありの最小費用流。Kは数字がループしているのが怖いが、適当に±100くらいの幅でdpしたら通ってしまった。Lは2行に置かれた多角形の差を持つdpで、2個飛ばしのimos法で高速化した遷移を2N回行うと答えが出る。Iに戻る。整数N=lrと積で表示したとき、|xl-yr|=2となるようなx,yを探し、kを復元したい。これは拡張ユークリッドの互除法を使うと何とかできるが、微妙に見つからない値もあるので、x-\frac r g,y+\frac l gとちょっとずらしたところ(gは最大公約数)もチェックしてみた。小さいケースを全部試して通ったので提出、AC。

Mも解けなかったので飛ばし、N。最初はO(\min(\frac{N^2}{K},NK\log N))で解こうとしていたが、TLEが全然取れない。残り時間も少なくなってきた中、ふと2次元セグメント木で書けることに気づく。dpの更新順を逆にすると、自分が持っている区間取得の2次元セグメント木で十分対応できたので、それを実装してAC。

解説を読む。Jのdpは結構面白い。Kの想定解はなるほどな~という感じ。そもそも隣接項の差の絶対値をとったものについて、総和の半分が操作回数となることに気づいていなかった。Iは答えの関数が乗法的関数らしく、素因数ごとに確かめることで答えが必ず2べきであることがわかる。実験でもそれっぽさは出ていたが、理論的にはわかっていなかった。

コードゴルフをする。Aはdcで場合分けを頑張る。今のところはN-2014を計算し、3になったら0に置き換え、1,2だったら1を足し、最後に0とmaxを取って1を引いている。Bは解説の式をRakuで書く。Cも解説にある方針で、-1A_1に置き換えて実際に中央値を求めるコードをPerlで書いた。DはRuby。EはPerlで、なかなかTLEに苦しんだ。他に、今のところHをRubyで、IをPerlとfactorコマンドでゴルフしてある。

このコンテストはAtCoderのトップページから辿れないので、AtCoderProblemsでもatgolferでも専用のコードを用意してクロールしている。そのためのプルリクエストを出しておいて、atgolferのほうは自分でマージしてしまって早速botに反映しておいた。

github.com

昨日投稿した合格体験記の中で、院試の共通問題3番(3)が解けなかったという話をしたが、今朝方針がリプライされていた。自分でちゃんと細部を詰めてみると納得がいったので、証明を追加して記事を更新しておいた。わかってみるとそれはそうという感じがするが、試験中に解けなかったのは確か。

東北大学大学院理学研究科 数学専攻 合格体験記 - kotatsugameの日記

午後9時からARC125に出た。

AtCoder Regular Contest 125 - AtCoder

4完遅解き。頭が回っておらず、BもCもDも均等に30分くらいかけてしまった。

Aはすぐわかった。最初にちょっと回したら、あとは小刻みに振動させるだけになる。丁寧に実装してAC。

Bは式変形を頑張ると、d^2\le x^2-N-1を満たすようなx0\le d\lt Nそれぞれに対して数え、和をとる問題に落ちる。条件がx\ge d+kと同値になるようにkを定めると、対応するdの範囲(の下側)がd\ge\left\lceil\frac{N+1-k^2}{2k}\right\rceilになるので、k\sqrt Nまで動かしつつ範囲ごとにまとめて数えた。かなり大変だった。

Cは最初に(3,2,1),(5,4),(8,7,6)のようなブロックに分かれる構築をしてWAを貰い、そこからずっと悩んでいた。この1を2番目に持ってこれることに気づいて愕然。実装ミスでさらに1WAした。

Dは、部分列dpっぽく考えると、スキップしたものと同じ要素を直前と直後で取らないような遷移だけすれば数え上げられる。あまり詰めずに書き始めたら全然答えが合わなかった。ちゃんと考え直すとセグメント木またはBITの区間和で書けて、スキップする区間の直前の要素の条件はダメな位置の値を0に戻すことで達成でき、直後の要素の条件は取得範囲を絞ることで対応できる。

Eを考えていたが一切わからず、コンテスト終了。赤になってから2回のARCはどちらもひどい順位を取ってしまっており、かなり絶望的。

コードゴルフをする。Aは手つかず。Bはdc。微妙にTLEしていたがコードを縮めると通った。dcにおけるループは再帰関数で書かれるが、では関数呼び出しは内部でどのように行われているかというと、コマンド文字列を毎回evalしているのである。なので、ループ用関数のコードが短くなれば、その分実行時間も短くなるという寸法だ。CはRuby。DはとりあえずC++で清書したものが最短になっている。

TCB39が終了していた。結果発表前、8問時点の結果では僕より点数が高く解答時間も短い人が数人いたが、蓋を開けてみると全完者は10人、その中でも自分は2位に20点差をつけ、合計解答時間でも最速と文句なしの優勝だった。かなり気分がいいが、それだけに理論値を逃したことが悔やまれる。

10問目はかなり難しかったらしい。上のほうで書いた判定方法を思いついたのは、まさに天啓という感じだったが、これは実際どこかのAGCの問題で出ていたという話を聞いた。どの問題かはわかっていない。

夜、日記を書く。明日月曜日はついにワクチン2回目の接種をする日だ。1回目ですでに副反応がだいぶ厳しかったので、今回はちゃんと買い物をして備え、しばらくは家でおとなしくしていたい。1回目の副反応は喉元を過ぎたので熱さを忘れてしまったが、確か冷えピタがかなり欲しくなったことを覚えている。ほかにもTLを見て、解熱剤(カロナールがいいのか?)とゼリー飲料も買い込んでおくべきと判断している。