読書記録(2022)

kotatsugame.hatenablog.com

1月

  • 2日
    D級冒険者の俺、なぜか勇者パーティーに勧誘されたあげく、王女につきまとわれてる3
  • 3日
    VRゲーで最強無双の少年、現実にステータスが同期し人生逆転
    劣等眼の転生魔術師6
  • 4日
    クラスで2番目に可愛い女の子と友だちになった
    エプロンの似合うギャルなんてズルい
  • 5日
    神狩1〈上〉
  • 6日
    公務員、中田忍の悪徳
  • 7日
    機械音痴な幼馴染が我が家でリモート授業を受けているのは、ここだけの秘密。
  • 8日
    最強魔法師の隠遁計画14
  • 9日
    いずれ水帝と呼ばれる少年
  • 10日
    私立シードゥス学院III
  • 12日
    『ずっと友達でいてね』と言っていた女友達が友達じゃなくなるまで
    友人に500円貸したら借金のカタに妹をよこしてきたのだけれど、俺は一体どうすればいいんだろう
    転生魔王の大誤算4
  • 13日
    前世は剣帝。今生クズ王子3
  • 15日
    俺は星間国家の悪徳領主!2
  • 16日
    俺は星間国家の悪徳領主!3
  • 17日
    俺は星間国家の悪徳領主!4
    西野 ~学内カースト最下位にして異能世界最強の少年~9
  • 18日
    プリンセス・ギャンビット
  • 20日
    お隣の天使様にいつの間にか駄目人間にされていた件5.5
    VTuberなんだが配信切り忘れたら伝説になってた3
    青のアウトライン
  • 21日
    純白令嬢の諜報員
  • 22日
    デート・ア・ライブ アナザールート
  • 27日
    パシられ陰キャが実は最強だった件
    辺境都市の育成者5
  • 29日
    美少女エルフ(大嘘)が救う!弱小領地
  • 31日
    犯罪社会学者・椥辻霖雨の憂鬱2
    神狩1〈下〉
    カワイイけど慎重すぎるお嬢様の笑わせ方

2月

  • 2日
    宅録ぼっちのおれが、あの天才美少女のゴーストライターになるなんて。
  • 3日
    宅録ぼっちのおれが、あの天才美少女のゴーストライターになるなんて。2
    陰キャだった俺の青春リベンジ
  • 15日
    『ずっと友達でいてね』と言っていた女友達が友達じゃなくなるまで2
  • 17日
    護衛のメソッド2
    純白と黄金
  • 19日
    今日も生きててえらい!
  • 20日
    初恋のお姉さんを今度養うことになりまして
    最強魔術師の弟子は冒険者ギルドの始祖となる
  • 24日
    一生働きたくない俺が、クラスメイトの大人気アイドルに懐かれたら1

3月

  • 11日
    神々の権能を操りし者2
    創成魔法の再現者1
  • 12日
    迷子になっていた幼女を助けたら、お隣に住む美少女留学生が家に遊びに来るようになった件について
  • 15日
    超能力に目覚めたボッチが政府に呼び出されたらリア充になりました
  • 17日
    リモート授業になったらクラス1の美少女と同居することになった
  • 23日
    かくりよの宿飯 十二
  • 26日
    異世界でチート能力を手にした俺は、現実世界をも無双する10
  • 29日
    私より強い男と結婚したいの
  • 31日
    継母の連れ子が元カノだった8

4月

  • 2日
    公女殿下の家庭教師11
  • 18日
    男子だと思っていた幼馴染との新婚生活がうまくいきすぎる件について
  • 23日
    鴉と令嬢
    俺は星間国家の悪徳領主!5
  • 24日
    自炊男子と女子高生
  • 30日
    王様のプロポーズ2

5月

  • 3日
    転生ごときで逃げられるとでも、兄さん?3
  • 6日
    時々ボソッとロシア語でデレる隣のアーリャさん4
  • 10日
    最凶の魔王に鍛えられた勇者、異世界帰還者たちの学園で無双する2
  • 11日
    英雄と賢者の転生婚1
  • 24日
    お隣の天使様にいつの間にか駄目人間にされていた件6
  • 26日
    デート・ア・ライブ アンコール11
    僕たち、私たちは、『本気の勉強』がしたい。
  • 28日
    好きで好きで大好きなので、いっしょに好きを伝えたい

6月

  • 23日
    灰原くんの強くて青春ニューゲーム2
    才女のお世話3

週記(2022/06/20-2022/06/26)

06/20(月)

午後1時半起床。ここ最近覚えがないくらいスッキリとした目覚めだった。あとは今日中に週記を書き上げて投稿できれば完璧。

今週のチュウニズムのアップデート情報が流れてきた。「泥の分際で私だけの大切を奪おうだなんて」が追加されるらしい。少し前にMVを再生してドハマりし、数日ずっとループしていた記憶がある。歌が良いのは当然として、イラストの女の子の表情もどれも非常に良い。嫉妬したり、見下したり、憔悴したり。三つ目はもう少し別の表現もありそう。ジャケットやサムネになっている堕天後のイラストの表情を言っている。

www.youtube.com

生協に行ってパン類を買い、帰宅して午後3時半からミーティング。最近ペアプログラミングをしていた人が学習の進捗を報告するのを聞いていた。その人からかなりお褒めの言葉を頂いて嬉しい。自分からもいくつか意見や懸念点を伝え、これからどうするか話し合っている途中で1時間が経過したため、話を切り上げて定例会に移った。

定例会では特筆することはなし。最近ずっと少しコードを書き換えて学習を回すのを繰り返していただけなので、報告すべき進捗がない。ただここでも先ほどの方の進捗報告で僕の名前が出てきたので、それに便乗する形で少しコメントを加え、内容をかさ増しした。勉強会は自然言語処理の話。以前AlphaCodeの論文を読んだときもよくわからなかったし、今日の発表を聞いて理解が進んだかというと、あまり……という感じ。もちろん発表ではなく僕に問題がある。理解したければ手を動かす必要があるのだ。

課題レポートを錬成する。今日期限で残っているのはゲーム理論だけ。教科書の今回の章は前回同様発展的な内容が多く、課題の問題が発展的ではない部分、つまり章の残りカスみたいな部分からしか出ていなかったので楽勝。パパっと終わらせて日記を書き始める。午後11時を回って何とか完成し、投稿した。

先週日曜日のOpenCup代理コンテストの解説を読んだ。ただし取り組んだ問題だけ。特にA問題はいろいろ知見が得られたので、ここに書いておきたい。「頂点数Nで辺が2NK本(以上)の無向グラフから、その部分グラフであって二部グラフかつ各頂点の次数がK+1以上になるようなものを構築せよ」という問題。今の表現は先週の週記に書いたものよりわかりやすくなったはず。

自分のアプローチは、各頂点の次数が2K+1以上になるようにグラフの頂点を削除した後二部グラフにするというものだった。逆で、二部グラフにしてからグラフの頂点を削除するのがよかったらしい。まず事実として「M辺の自己ループを持たないグラフは『辺をM/2本以上持つ二部グラフ』を部分グラフに持つ」ということがあって、こうして作った辺がNK本以上ある二部グラフから次数K以下の頂点を削除していくと、いつか全頂点の次数がK+1以上になっている。この操作でグラフが空にならないことは先週の週記でも書いた。Diestel Prop 1.2.2。

さて、先ほど登場した事実を示そう。といっても実は簡単。頂点をランダムに塗り分けると各辺が二部グラフに含まれる確率が一律で1/2であるため、すべての塗り分けについて辺の数を数えたものの平均がM/2本となり、特にM/2本以上の辺を持つ塗り分けが存在することが言える。つい最近、次数に関してこうやって\max\ge{\rm mean}\ge\minという議論を行った記憶がある。さらにM\gt 0のときM/2よりstrictに大きくできること、またMを固定していろいろグラフを変えたとき、「二部グラフとして持てる辺の数の最大値」の最小値がM/2+O(\sqrt M)オーダーであることを熨斗袋さんに教えてもらった。以下のツイートとそのリプライ。あくまで\ThetaではなくOであるはず。

そのような二部グラフの構築について、解説では乱択して適当に頂点を塗り分けた後1点flipを繰り返していた。しかしもっとオーダー良く決定的に解けるらしい。これまた熨斗袋さんのツイートによる。すでに集合に振り分けられた頂点への辺だけ考えると必ず半分以上を二部グラフに含めることができて、全部終わった時にはM/2本以上になっているということ。

来週月曜日午前中が期限の、ハードウエア基礎の課題レポートを錬成する。講義スライドは電気回路の計算を入念にやっていて、高校物理を忘却してしまった自分では何を言っているのか理解できなくなってきた。しかし練習問題と解答がいくつか載っていて、それをガン見しつつ手を動かすと課題で出るレベルなら何とかなった。スライドを眺めながら絶望していた時間が長く、課題を解くのはすぐできた。僕の理解では必要ないパラメータが問題文で与えられていたのが不安。

シャワーを浴びて2時間ほど日記を書き、布団に入った。TLでDMOJというコンテストサイトの話題が出ていて、ちょうど今Ratedのコンテストが開催されている様子。期間には余裕があるので、明日あたり出ようかなと考えた。午前7時就寝。

Home - DMOJ: Modern Online Judge

06/21(火)

午後1時半起床。

チュウニズムのアップデート情報がまた流れてきた。ありえないくらい最高すぎる。まず「フォニイ」の追加が嬉しい。ただそれよりも「BlackFlagBreaker!!」の追加に驚いた。音ゲー界隈と関わりの深い人たちが作った曲なのでいずれは追加されると思っていたが、さすがにちょっと速すぎて信じられなかった。もちろんこれも非常に嬉しいことである。

昨日寝る前に見たDMOJにアカウントを作り、少し問題を解いてみた。CodeChefのとき日記に書いたような確認をここでもやってみたが、正直もう細かい仕様を覚えていられないので、AtCoder以外ではいつもlong longを使うし、main関数の型もしっかり書くようになっている。

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

週記(2021/09/20-2021/09/26) - kotatsugameの日記

いったん大学生協に行って買い物。入荷メールが届いていたラノベを受け取ろうとしたら1冊が見つからなくて、しばらく探してもらっていた。オーバーラップ文庫。途中でこのレーベルが毎月25日発売日であるということに気づいたため、入荷メールの間違いということになった。最近予約でばかり買っているのでレーベルごとの発売日が頭から抜けてしまっている。

帰宅し、午後6時ぐらいからBCI Programming Contest 1 Seniorに出た。4日間の期間が用意されていて、その中から適当な3時間を選んでコンテストに参加することができる。参加終了まで順位表は見られない。想像していたよりかなり難しかったし、順位表が見えないので本当に今取り組んでいる問題が難しいのかにいまいち自信が持てず大変だった。

BCI Programming Contest 1 Senior - DMOJ: Modern Online Judge

S1はまずa_1を決定する。これまでに決定した数で作れるペアの和を全部削除しておくことで、その時々で最小のものがa_1+a_iの形をしているとわかる。あとは繰り返し。

S2からもう難しい。0xの距離がxに等しくなるような最大のxは、pの小さいほうから二つをp_1p_2としてL=\lfloor(p_1+p_2)/2\rfloorとなる。また、0L+1の距離を聞いてL-1Lか判定することで、p_2-p_1の偶奇を特定できる。p_2-p_1が偶数のときはL-1L+1が、奇数のときはLL+1がそれぞれ0から等距離にあるとわかる。もっと言えば、0からp_1までの地点からは等距離にあって、p_1より右で2点より左(2点を含む)の位置からは等距離にない。よってこの範囲を二分探索することでp_1が特定できる。p_1Cの距離を聞くことで、pの最大値もわかる。

あとは内側を探索。ある開区間(l,r)について、その左右で最も近いp_l,p_rがわかっているとして、(l,r)に別のpがあるかを判定するには、m=\lfloor(l+r)/2\rfloorp_lの距離aを聞けばよい。p_lまたはp_rから直接向かうよりも短くなるならm-aまたはm+apの一つとなり、(m-a,m+a)にはpがないこともわかる。これで(l,r)が二分割されるので、それぞれで再帰的に解く。1時間くらいかかった。

S3が初手から全く分からなかったので、S4に進んだ。A\oplus B0を場合分けしてXORする方針。A\oplus BのMSBと、A\cdot(A\oplus B)(ただし\cdotはbitwise AND)のMSBが比較できれば良い。MSBを検出するため、ある数を右・下・左にずらしてbitwise ORしまくることでMSB以下のビットをすべて立てた数を作った。数Xに対してそのような操作をした後の数をf(X)とおくと、f(A\oplus B)\oplus f(A\cdot(A\oplus B))が非ゼロになるのとMSBが等しくないのは同値。こうして得られた数にさらにfを作用させ、A\oplus Bとのbitwise ANDを取ることで、A\lt BならA\oplus BになってA\ge Bなら0になるような数が得られる。つまり、f(f(A\oplus B)\oplus f(A\cdot(A\oplus B)))\cdot(A\oplus B)

さて、fは計算用にレジスタを一つ破壊する。AA\oplus Bを保存しておいて、さらにfを同時に二つ持つ必要があるので、レジスタは五つ必要になって90点までの部分点が得られる。これを実装して提出。しかしWA。自前でチェッカーを書いても全然落ちなかったので、試しにfの計算を賢くやっていたつもりの部分を愚直にやったら通った。ずらしてbitwise ORするときに16\rightarrow 8\rightarrow 4\rightarrow 2\rightarrow 1と幅を狭めることで効率的に全部埋められると思っていたところを、1\dots 31を全部行う方針に。何がダメだったのかわからない。

残り20分もないため、ほかの問題は無視してこのまま満点を考える。まずf(A\oplus B)を作り、適切にずらしてbitwise ORを繰り返すことでこれのMSBだけ下ろした数を得る。その数をXとし、またY=A\cdot(A\oplus B)とする。Y\oplus(Y\cdot X)=Y\setminus Xを計算した結果が非ゼロになるのと、A\oplus BYのMSBが等しいことが同値になる。あとは先ほどと同様にすれば、A\gt BならA\oplus BになってA\le Bなら0になるような数が得られる。こちらのアルゴリズムレジスタ四つで実装できる。

残り時間が少ない。サッと書いてチェッカーに投げると合わず、焦りながら何度も読み返したものの結局合わないまま終わった。直後に、先ほどはA\lt BならA\oplus Bになっていたところが今はA\gt BならA\oplus Bになるということに気づいた。非常に悔しい。

公開された順位表を見に行くと現時点で9位。自分より上の人は全員S3で満点を取っているので、実は解けなければならない問題だったらしい。今考えてみても全然わからない。S4の満点は二人しかいないので、余計に悔しくなってきた。総じて良い結果ではない。コンテストが難しかったこともあってしばらく放心状態だった。

終えてから日記のコンテスト部分を書き、戻ってS3のupsolveをした。あまりに無理すぎて途中椅子で寝入ってしまったが、何とかひらめきを得ることができた。

最初にX\leftarrow X\bmod{\sum_i a_i}としておく。まず、バスもバス停も同じ色のものが固まって同じ順番で並んでいるのが最適とエスパーする。固まっているほうが明らかに嬉しくて、バスとバス停が列として一致する瞬間があるとさらに嬉しそうだから。あとは時刻0の時点でいくつずれているかの問題になって、部分点はずらす幅を全探索してバスごとに寄与をカウントしても通る。ここまではコンテスト中に考えていたこと。ただし実装はしなかった。

最大の非自明ポイントとして、このずらす幅はおよそX/2と決め打ってよいらしい。考え方としては、全くずれていない状態のとき答えに対する寄与が最も大きくなり、そこから左右に行くごとにどんどん減っていくはずだから、時刻0からX-1の間に達成するずれ幅の区間[-\lfloor X/2\rfloor,\lceil X/2\rceil)などとして\pm 0を含みつつその左右がだいたい同じ長さになるようにしたくなる、というものだった。部分点のコードを書き換えて提出してみると当然のように通ってひっくり返った。

あとは答えを求める部分の高速化。気合いが必要。ある色について、その色のバスが時刻0からX-1の間にどの位置をどれだけ通るかの分布は台形になるため、傾き+1,\pm 0,-1の部分に分割して、それぞれその色のバス停と重なる部分を求めて答えに足す。もう見るからに面倒そうなことを言っているが、実装してみると案外すらすら書けた。一発でAC。確かにこれは解けるべきだったかもしれない。しかしこれを通していたらS4は部分点も間に合わなかっただろう。

upsolve後はYouTubeに気を取られつつ昼間までおすすめのなろうまとめを書いていた。朝あたりに指導教員の先生からメールが来て、今週木曜日のセミナーがキャンセルになった。よって思いっきり生活リズムを乱すことができる。正午就寝。

そういえば今日は夏至だったらしい。コンテストへの参加が終わったあたりでTLを見て気づいたが、日記のその部分に割り込ませるのが不自然だったのでここに書いておく。

06/22(水)

午後9時起床。ICPCの誓約書を提出した。また昨日参加したコンテストが終了していた。16位まで落ちて、最初のレーティングは2320。

YouTubeのチャンネルにコミュニティ投稿ができるようになったと通知が来た。登録者数500人で開放される機能らしい。思いがけない特典があって嬉しい。最近、YouTubeの動画の共有ボタンを押すと「投稿で共有」という謎の表示が出るようになっていたが、これもコミュニティ投稿が可能になったことによるもののようだ。

おすすめのなろうまとめを書く。昨日と同じくらい進められれば今日終わりそうということで頑張っていた。午前9時になってついに完成し、投稿した。

kotatsugame.hatenablog.com

前の記事から継続して紹介しているのが21作品、ここ1年で読んだものから26作品選んだ。ジャンル分けについては、二次創作が多いし、どうしても全部主人公最強モノという観点で見てしまっているので、今回はすっぱり諦めることにした。

こうして改めておすすめできるものをまとめてみると、一般にも評価が高い作品ばかり集めてしまったなという感想になる。ではこの記事の意義はどこにあるのかという話だが、ジャンルを問わず一人の人間が好きなものを集めたという点にあると考えている。特定のジャンルの作品を読みたいなら自分で検索して評価順に並べればよい。そこから離れ、別のジャンルなりあまり知らない作品の二次創作なりにこの記事を読んで手を出す人がいれば嬉しい。

学食で食事し、帰宅してからはしばらくラノベを読んでいた。午後2時就寝。

06/23(木)

午後10時起床。しばらくYouTubeを見ていた。

www.youtube.com

www.youtube.com

周央サンゴさん、かなり面白い。普通にやっていても面白いうえ、上手なのに題材が意味不明な声劇が最高。また朗読の際の声を人間が発音していることに驚くし、イラストとまったく合っていないように思えて笑ってしまう。

ラノベを2冊読んだ。まず1冊目、「灰原くんの強くて青春ニューゲーム」2巻。1巻に引き続き非常に良かった。当時日記に「微妙な緊張感がある」という感想を書いて、たぶんこれは態度を取り繕っている主人公がボロを出さないかドキドキする状態を指していたと思うが、1巻ラストの展開を受けて2巻ではかなり緩和されていた。依然としてまだあまり関わりのない人からは完璧超人という扱いを受けているものの、主人公はこれを不思議がりつつ軽くスルーするため、素直に主人公を引き立てるシーンとしてニヤニヤできた。この巻からは仲間内の恋愛模様について焦点を当てている。特に、心に決めた人が1巻から変わっていない主人公に対して積極的にアプローチを掛けるヒロインの話。まあこの人に対してはラストで一段落ついたため、不安定な状態は脱したように見える。しかしその過程で周囲の様々な関係が表出してきて、次の巻はどれだけ思惑が入り組むのか楽しみである。

2冊目、「才女のお世話」3巻。面白かった。幼馴染であるヒロインがようやくメインを張る。その幼馴染が抱える問題を解決しようと奮闘しているうちに、主人公も入学以来いつの間にか生じていた自身の問題点に気づく。後者については、別に叙述トリックというわけではないもののラノベ読者から見ると結構盲点な気がして、そういう展開になるのかと驚いた。ラストシーンは多少テンプレ展開に見えるが劇的でよい。しかし剣道の試合の最中に大声で声援を送るという描写は受け入れ難かった。それなしでは確かに味気ないので展開上の要請はありそう、とはいえもう少し気を使ってほしいところ。

日記に本の感想を書き、学食で食事して、それからなろうを読み始めた。午後3時半寝落ち。

06/24(金)

午後11時起床。実は明日土曜日は昼からICPC模擬国内予選らしい。完全に生活リズムが合っていない。大学から出る予定なので、とりあえず何も考えず注文した生協の冷凍弁当の配達を月曜日に振り替えてもらえるようメールを出した。

今日は横たわったまま過ごすことでできるだけ早く寝ようとし、布団でなろうを読み始めた。午前3時くらいになって1作読了。「隣に住んでる聖女様は俺がキャラデザを担当した大人気VTuberでした」。

https://ncode.syosetu.com/n5518hm/

非常に面白かった。そもそもとして、「Vtuber」と「半同棲」という僕が好きな題材を合体させているのだから気に入らないはずがない。特にVtuberパートが好み。タイトルにもある通り主人公はイラストレーターで、担当したVtuberに誘われて親娘コラボを繰り返し人気となっていた。二人が思いがけずリアルで対面することから話が始まるのだが、それ以前の設定だけで自分のストライクど真ん中。ファンに認められているくらい仲の良いVtuberの男女コンビは最高。

設定の話ばかりして内容に触れていなかった。Vtuberモノとしての配信パートと半同棲モノとしての恋愛パートをそれぞれだけ見ても十分面白い。前者については主人公がLive2Dの肉体を手に入れるくだりが好み。後者については学校、つまり他者の目があるところでも二人が距離を近づけていく様子が良い。いずれ二つのパートが大きく交わる展開もありそうで期待している。すでに描かれた部分としては、オフコラボのシーンがそれの一例になるだろうか。今のところおおむね独立して進んでいるように思う。

DMOJでまたRatedのコンテストが開催されていることに気づいた。金曜日から月曜日までの日程だが、土日はコンテストで埋め尽くされているし、月曜日はインターンだったり課題だったりでこれまた予定を入れたくないので、今日参加しておく必要があったらしい。明日の予定を鑑みて今からでもギリギリ大丈夫だと判断し、午前3時半から3時間で参加した。内容や感想については、今日の日記を公開する時点でコンテストが終了していないので来週の週記に書こうと思う。

DMOPC '21 June Contest - DMOJ: Modern Online Judge

公開するのは来週だが、文章は今日作成する。書き終えるともう午前8時を回っていた。布団に入り、そこから何を思ったかなろうを2時間以上読んで、午前10時半就寝。

06/25(土)

午後1時起床。死にそう。ノロノロ準備して出発し、学食で食事しつつ山に登った。信じられないくらい暑かった。

ホスフィンが大学の演習室を確保してくれたので、そこからICPC模擬国内予選に参加する。午後2時から3時間のコンテスト。これについては参加記を書く予定なので、日記ではあまり触れない。投稿したら以下にリンクを貼っておこう。全体3位だったことだけ、かなり嬉しいのでここにも書いておきたい。

午後6時前に帰宅。即座に布団に横たわってABCまで仮眠を取ろうとした。しかしうまく眠れず、結局2時間横たわっただけになってしまった。ずっと目が冴えていたので、肝心の頭が休まった気が全然しない。シャワーを浴びて眠気を少しでも取り、午後9時からABC257。

NS Solutions Corporation Programming Contest 2022(AtCoder Beginner Contest 257) - AtCoder

Aはパッと見よくわからなかったので実際に文字列を作って解こうとし、C++で書き始めたところで\lfloor(X-1)/N\rfloor+1番目のアルファベットを出力すればよいことに気づいた。そのままC++で書き上げ、ACを確認した後、dcでも提出しておいた。Bは愚直に。CはS_iW_iを組にしてW_iでソートし、区切りをずらしつつ差分更新する。同じ体重の人を区別できないことに注意。このあたりの問題にしてはちょっと難しいなと感じた。

Dも難しい。i\rightarrow jj\rightarrow iでジャンプするためのSの下限が異なり得ることを見落とし、最小全域木を求めようとした。無向辺ではなく有向辺だと思わなければならないと知り、考察をやり直す。始点を1点決めると、そこから各点に到達するためのSの下限がdijkstraで計算できる。辺の数がO(N^2)なのでO(N^2\log N)dijkstraN回行った。実装途中で答えが最大4\times 10^9とint型の最大値を超えることに気づき、コストの変数をlong longに修正したのだが、し切れていなかったようで1WA。

Eは最初に9を連打することを考えて、それより桁数を増やすほうが得だと気づいた。桁数の最大値は\lfloor N/\min C\rfloorになるので、これを達成できる限りで最上位桁から数字を大きくしていくのがよい。実装も簡単で、D問題のACから2分ちょっとで通った。見た目からdpっぽさも感じていたので拍子抜け。Fは、結ぶ街の片方が未定のテレポーターを超頂点0に繋がる辺だと見なしてグラフを作ればよい。頂点0iを同一視したときの1からNまでの最短距離を求めることになって、1\rightarrow N1\rightarrow 0\rightarrow i\rightarrow N1\rightarrow i\rightarrow 0\rightarrow Nの距離の最小値となる。1Nから各頂点への距離をそれぞれ前計算すればよい。GはZ-Algorithmとrange chminで実家dpができる。range chminのほうは優先度付きキューで、今見ている要素への作用素を持つことで実装した。

Exは難しい。kyopro_friendsさんの解説と全く同じ式変形によって、\left(\sum x\right)^2+\sum yを最大化する問題に帰着した。よくわからないので適当な貪欲を試してみる。(x,y)の降順にソートして値を順に追加し、K個を超えたら取り除いたときの値の減少量が最も小さいものを取り除く貪欲を書いてみると、70ケースくらいまで通った。もしかしてACかと思いかなり興奮したものの、蓋を開けてみると6ケースWA。次に(y,x)の降順にソートして同じことをすると、5ケースWAに減った。最後に、(x,-y)の降順にソートして連続するK個を選ぶコードを追加してAC。

Editorial - NS Solutions Corporation Programming Contest 2022(AtCoder Beginner Contest 257)

最後の場合分けは、\sum xをいろいろ試しつつ\sum yを最大化しようとしている。これまで値を1個だけ交換してきたが、2個交換するときどうなるか計算してみると、xが交換したペアの両方で増えているか減っていれば1個だけ交換するのよりよさそうだったので、積極的に\sum xが減る方向に動きたかったのだ。

80分弱で全完、Dの1WAとExの4WAで5ペナ、4位。Dの想定解は二分探索だったらしい。考えもしなかった。Exの解説は大変そうなことが書いてあって、僕のコードに正当性がないことしかわからない。

コードゴルフ。A問題はAC直後に提出したdc 9Bが最短でよく、ちゃんと速度でも勝てていた。BはPerl。CはRubyで書いたがPerlに大敗。EはRubyで負け。他は手付かず。

眠気をこらえ、午後11時半からCGR21に出た。

Dashboard - Codeforces Global Round 21 - Codeforces

Aは\max_i (a_i\mid z)が答え。Bは2手で必ず可能なので、0手と1手の判定ができればよい。0手は自明で、1手は両端から続く0を削除したとき0が残らないことを確認する。Cは逆の操作が可能なので、abに操作を施して何らかの正規形にし、一致するか判定すればよい。具体的には1番目の操作で分解できるだけする。一応ランレングス圧縮して保持したが、普通に持っても間に合うくらいの長さにしかならないようだ。Dは右にしか進まなくてよいと思い込んで貰うdpをした。左向きの累積max・minを持って、それが更新される点だけdpの値をセグ木に乗せておく。あとは区間MINで今見ている点までの距離が求まる。

Eは各マスに対してそこに置かれた人形を消すのに何手必要かを手計算してみると、寄与の流れが見えてきた。i+1行目の手数の列からi行目の手数の列を求めるとき、長さがa_iになるよう0埋めし、全体に+1したあと右から累積和を取るという操作をしていることがわかる。この+1がマス(0,0)にたどり着くときいくつになるか考えればよくて、これはマス(x,y)から左と上への移動を繰り返してマス(0,0)に到達する方法だから\binom{x+y}{y}となる。よって求める値は\sum_{x=0}^n\sum_{y=0}^{a_x-1}\binom{x+y}{y}となり、内側の総和がよく見る形。Wolfram|Alphaに投げたらちゃんと閉じた式になった。

Fはまず各頂点kについて頂点たちをkからの距離が同じものでグループ分けしておく。次に根を1点固定し、その子、つまり根から距離1にある頂点の集合を考える。どれかわからないので全探索する。実は、ここまで決めると木としては高々1通りになる。なぜなら、親pと子uの組が与えられたとき、uの子はuからの距離がpと同じになるからである。先ほど分けたグループからpを含むものを見つけ、p以外をuの子とすることでBFSのようにして木を下っていける。途中ですでに見た頂点が出現したらダメだったということ。最後まで決めきれたら、改めて条件をチェックして出力する。グループ分けするときUFを使っていて、d(u,k)=d(v,k)かつd(v,k)=d(w,k)なのにd(u,k)\ne d(w,k)であるようなケースに引っかかってしまい1WA。

残り1時間ちょっとはGを考えていて、端から決めるときの計算を関数だと思ってセグメント木に乗せられそうだったのだが合成が書けず終了した。

システスは全部通って速めの6完で21位。レートは2875→2964(+89)。あと1回上振れすればLGMだが相変わらず遠く感じている。

Dの右にしか進まなくてよいというのはあまり正しくない。解説では「常に右の最も遠い点に進むのが最適」という事実が紹介されていて、これを含んでいるからたまたま正しくなっていたようだ。右にしか進まなくてよいことを証明するためには、途中で左に進むような経路を取ってきて右にだけ進む経路で再現するのが一般的だが、かなり難しそう。少し取り組んでみたところ左に何回進むかなどで場合分けが大量発生し、早々に放り投げた。

Eは各マスに何個人形が置かれるかカウントするのでも答えが求まる。マス(x,y)に置かれる人形の数を求めるときは、上に書いたのと全く逆の(0,0)から右と下だけに進んで(x,y)にたどり着く方法だと見れて、値は同様に\binom{x+y}{y}になる。Fは根と子を一つ、つまり1辺決めてもよかったらしい。そもそもグループ分けが正しくないことに気づかず使っていたのが問題。計算量的には余裕があるので、子を探索するときに入力を直接見る方法でO(n)かけてもよかった。

かなり眠い。布団に入って少しなろうを読み、午前4時半就寝。

06/26(日)

午前9時半に起きてしまった。かなり眠気が残っていたのにうっかりスマホを取り、TLを見て、二度と眠れなくなった。布団に横たわったままずっとなろうを読んでいたが、一向に眠れる気配がないので、午後2時半に布団から出て、しばらくICPC模擬国内予選の参加記を書いていた。

午後4時からOpenCup。今週も代理コンテストで、ARCと被せないため開始をこの時間にするということで合意が取れていた。今日のコンテストタイトルはPTZ 2021 Summer Day 2, NAC 2021。ちなみに代理コンテストは五つしかなく、これが最後である。

Petrozavodsk Summer 2021. Day 2. The American Contest - Dashboard - Contest - QOJ.ac

チームとしてMFLDJCEAGを解いた。僕は最初2時間をAに費やし、解けず、次の2時間半でGを解いた。ずっと椅子を温め続けていたので非常に苦しいコンテストだった。Gが通ったのもよくわかっていないので消化不良気味。Aは考察の初手が違っていて、後半は僕が考えていたことと同じことをやるようなので少し悔しい。チームメイトが通してくれたので感謝。

Gについて。クエリをaの昇順に並べ、先頭から数列を展開していく。展開後の長さは前計算できるので、クエリに関係ないならスキップする。このとき、展開後の列に含まれるkの個数というのをすべてのkに対して求めたくなる。値ns回展開するとすれば、k\le nに対して展開後の個数がks-1次式になる。sは非常に小さいので、多項式をBITに乗せれば区間和を取得することで個数が求められるようになる。

ただしa\le 10^9なので、途中をスキップしたとしても何項見ることになるのかがよくわからなかった。残りの展開回数が0回になってからようやくクエリの計算をしていたらTLEだったので、残り1回の時点で求めるようにしたら通った。このとき固定された順列に対して区間内のk以下の要素数が知りたくなったので、\logが2個つく重めのライブラリを持ち出したが、さすがに全部展開するよりは速かったのだろう。

直後、午後9時からARC143に出た。

AtCoder Regular Contest 143 - AtCoder

Aは、A\le B\le CとしてまずB=Cとなるように操作したい。つまりACから1引くのをC-B回繰り返すため、A\ge C-Bである必要がある。一度B=Cになりさえすれば、後はB回の操作で全部0にするのが最適。

Bは少し難しい。まず1番目の条件を満たさない数は各列の最大値である。列iの最大値をM_iとおいて、Mの最小値がi=i_mで達成されるとしよう。するとi\ne i_mについて、M_iと同じ行のi_m列目の数はM_{i_m}以下になる。今M_i\gt M_{i_m}なので、M_iと同じ行により小さい数があることが分かった。したがって2番目の条件も満たさないようなマスはあるとすればM_{i_m}だけである。あとはM_{i_m}を全探索して適当に組み合わせ計算。

Cも難しい。最初、選ぶ山がちょうど一つだと勘違いしていた。少しの勘違いもあり解けたと思って実装し、サンプルが合わず、誤読が判明して絶望。ただし、相手の操作を真似することを考えてA\leftarrow A\bmod{(X+Y)}としてよいという考察が変わらず適用できたので軽傷だった。そのような操作をした後A_i\ge Xなるiがなければ先手負け。まずこれでサンプルが通って提出し、WAだった。もうちょっと考えて、X\gt A_i\ge Yなるiがあると自分に手番が返ってくる可能性があることに気づいた。この条件を追加すると通った。

Dは案外あっさり解けた。(A_i,B_i)を辺と見たときに出現するループは、A_i\leftrightarrow B_i+N\leftrightarrow B_iと展開することで問題のほうのグラフでもループにできる。これをA_i\rightarrow B_iという有向辺だと思うと、二重辺連結成分だったものが強連結成分となるよう向き付けられれば最適で、実際dfs木を使えば達成可能。これは日記を書きつつ整理したうえでの表現で、コンテスト当時どのような閃きでdfs木にたどり着いたのかは記憶があいまいで再現できなかった。ともかく実装し、提出すると1ケースだけWAで絶望したが、頂点番号を0-indexedにしていなかっただけだった。すぐ出しなおしてAC。ちなみに実装テクとして、01のどちらがA\rightarrow Bかということには注意を払わなくてよい。全部逆にしても橋の本数は同じになるからだ。

Eは初手が完璧で一瞬で解けた。葉の石をどのタイミングで取り除くか考えると、親より前か後かという話になって、初期状態を見ることで決定する。またこれに応じて親の石の初期状態が変わったと見なせて、さらに以降その葉は無視してよくなる。このように葉を順に削除していき、最後に残る1点の状態を見ることで判定問題が解ける。また各辺についてどちらの端点の石を先に取り除くかという条件だけが操作列に要請されるので、辞書順最小の構築はトポロジカルソートを優先度付きキューで行うという典型問題になる。実装も特に手間取ることなく一発AC。

この時点で2位。Fに80分残すことができて、初の全完もあり得るかと思ったが、その後ずっと考えていても解けずに終了した。最後のほうは愚直と比較していて、N=7\{1,2,3,5,7\}\{1,2,3,6,7\}が数えられていないことに気づいたものの、最後に7を入れるかどうかの判定が難しいことに気づいて絶望。いや、N=7ならまだ何とかなっていた。しかしもっと大きな数になるともっと盛大に破綻していることに気づいて、今度こそ諦めてしまった。

結局Fは誰にも解かれず最終順位も2位。ARCでは最高。かかった時間がそれぞれ3分、7分、12分、8分、7分と、DEが自分でも信じられないくらい速かった。2ペナ出してしまったのが惜しいなと思っていたが、1位とは12分差なので惜しくもなんともない。3位とは10秒ちょっとの僅差だったので危なかった。

Eの判定問題は、初期状態における表が白い石の個数の偶奇を見るだけで解けるらしい。なるほど、葉から削除していくとその偶奇が変わらないことから確かめられる。コンテスト中は考えもしなかった。こういう顕著な性質が必要なく、むしろ想定解から外れていく罠になってしまう問題というのも面白い。

コードゴルフ。Aは2\times\max(A,B,C)\gt A+B+Cなら-1、そうでなければ\max(A,B,C)なので、dcで実装。Bは解説にある閉じた式をさらに整理し、(N^2)!-\frac{N!^2(N^2)!}{(2N-1)!}Rubyで計算する、コードをVimで書いている。さすがに(500^2)!は厳しいため\bmodを取った値を使うことになり、割り算が面倒だが、\frac{(N^2)!}{(2N-1)!}=\prod_{i=2N}^{N^2}iと求めることにするとかなり縮んだ。CはPerl。シンプルな条件に見えて結構面倒で、うまい表現が思いつかず微妙に長そうなコードを書いている。以降は手付かず。

もうあり得ないくらい眠い。しかし今週末出たコンテストはどれも非常に良い成績を残しているため、午前1時からのSRM832にも出ることにした。

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

Easyは面倒。まずcommandsを1回実行したとき各点を何度訪れるかカウントする。最初はcommandsの要素がめちゃくちゃ大きいことに気づかず愚直を書いていた。後から気付いて修正。周期がNなので、1\le i\le Nに対してi個先を通るのが何回かそれぞれ数えるのが楽だった。次に、commandsを1回実行するたびに進む数が求まるので、これをR回繰り返したときどの地点から何回commandsを開始することになるか数えた。こちらは元に戻る周期がNより小さくなる可能性があるが、Nだと思って計算しても問題ない。最後にO(N^2)かけて畳み込むと答えになる。始点に+1することを忘れずに。

Medも面倒。A=0の場合に解ければ差を取ることで答えになる。まず、Sの長さがBになるとき何桁の数を追加しているのか調べる。n桁のgoodな数は、1\dots n-2桁のgoodな数に対してn桁目のbitを立てたものになるから、その個数や含まれる1の個数が順番に求まる。桁数nを確定したら、「その桁が立っている状態で」下の桁が1\dots n-2桁のどれに該当するか調べていく。再帰的に繰り返すことで上位桁からどこが立っているか順に求まっていって、最後に中途半端な部分を調べる。非常に怖いので小さい値で愚直と比較したり、途中で桁数が大きくなりすぎたりしないか調べたり(58桁の数まで追加されるようだ)してから提出した。

Hardは簡単。i=1\dots Nの順でループし、Ai番目から左に見ていったときに初めて出現する値の位置を差分更新で列挙する。H=iなるクエリ[L,H)について、列挙した数であって区間[L,H)に含まれるものの和を求めることで、必要なtmaxの和が求まる。これは1点更新区間和のセグ木で実現できる。i=N\dots 1として同様のことを行えばtminも得られる。解法はすぐ出たものの実装に手間取って900点中600点くらいになった。

チャレンジの時間はARCのコードゴルフをしていた。全部通って全完8位、レーティングは2815→2848(+33)。highestである。

いよいよもって眠すぎる。日記をめちゃくちゃ溜めているが、かまわず寝てしまうことにした。さすがに今日睡眠失敗したのは痛い。午前3時半就寝。

おすすめのなろう小説まとめ Part2

kotatsugame.hatenablog.com

ジャンル分けは諦めました。コメントで大まかな展開に触れた作品もあるので、少しだけネタバレ注意です。

最終更新日:2022/06/23

増えたやつ

影の勇者の再冒険 ~~Re-Tale of the Brave~~

学校ごと異世界転移。その世界で勇者だったことを隠している主人公だが、それでも素の実力が十二分にあるため表向きの立場がガンガン上がっている。正体を隠しているという設定と、めちゃくちゃ強くて活躍しているという設定が両立されており、非常に好み。またほんの少しずつ周囲の人に正体を明かしていて、そのシーンごとに解放感があって気持ちいい。ただ非常に長いので内容は希釈されているように感じる。

https://ncode.syosetu.com/n5534co/

剣姫転生 〜エルフの娘は世界最強の剣士を目指す〜

無職転生の二次創作。重い話は全部原作主人公に押し付けてオリ主は自由に行動しているので、かなりストレスフリーに読めた。原作では本当にレアだった帝級や神級が大盤振る舞いされていて爽快感がある。

剣姫転生 〜エルフの娘は世界最強の剣士を目指す〜 - ハーメルン

SAOを真面目に攻略しない人々

短編集。「キリト君にゲーム作らせたら解決なんじゃないかな」が一番好き。決して本題ではないが、ゲームの難易度調整を重ねるうちに現実における体の動かし方に影響が出てきた描写が特に好みだった。

SAOを真面目に攻略しない人々 - ハーメルン

ウマ娘 ワールドダービー 凱旋門レギュ『4:25:00』 ミホノブルボンチャート

プレイヤーキャラクターの造形が好み。行動がRTA走者によって制御されるから基本合理的ではあるが、その中でもRTA部分で描かれなかった話から見える性格があって、サイドストーリーではRTA関係なく面白い小説が読める。その性格が如実に表れた「サイドストーリー:怒髪衝天」が印象的で大好き。

ウマ娘 ワールドダービー 凱旋門レギュ『4:25:00』 ミホノブルボンチャート - ハーメルン

ソードアート・オンライン ラフコフ完全勝利チャートRTA 2年8ヶ月10日11時間45分14秒(WR)

上のRTA小説とは違い、プレイヤーキャラクターはとことん合理的。こちらにもサイドストーリーと同等のものが用意されているが、そこでも効率的にゲームのクリア目標だけを達成しようとする主人公が描かれる。その完璧に取り繕われた外面で人を操っているのが好き。

ソードアート・オンライン ラフコフ完全勝利チャートRTA 2年8ヶ月10日11時間45分14秒(WR) - ハーメルン

もこたん→青ニート←その他大勢

ダークソウル由来の装備品や能力で無双しつつ東方Projectの世界で過ごしている主人公の話。古代スタートの要素もあり。不死となって枯れ切った主人公が原作キャラに向ける超然とした態度が好き。

もこたん→青ニート←その他大勢 - ハーメルン

正体不明の妖怪(になった男)、情緒不安定な百獣の腹心になる

ワンピースの二次創作。東方Projectクロスオーバー要素は主人公以外なし。主人公もワンピ世界で普通にあくどい海賊として成長していく。そのバロメータとして懸賞金がどんどん上がっていく描写がわかりやすく、興奮した。主人公の全力バトルは少なく暗躍多め。

正体不明の妖怪(になった男)、情緒不安定な百獣の腹心になる - ハーメルン

ヒエヒエの実を食べた少女の話

主人公勢力は善良な海賊(善良な海賊?)で、やがて成長していくと海運を牛耳ったりする。そうやって強大な組織を真っ当に運営している描写が好み。周囲の畏怖も良い。

ヒエヒエの実を食べた少女の話 - ハーメルン

じゃしんに愛され過ぎて夜しか眠れない

遊戯王の二次創作。圧倒的ドロー力でデッキをぶん回して勝ちまくるのが爽快。説明も細かいので、カードを知らなくても楽しめた。

じゃしんに愛され過ぎて夜しか眠れない - ハーメルン

黄金の経験値

MMORPGでラスボスのロールプレイをする主人公の話。周囲からNPCだと思い込まれつつ暗躍し続け、自勢力を強化したりほかのプレイヤーを手玉に取ったりする策略の描写がどれも読んでいてワクワクする。途中から積極的に表舞台に立つようになるものの、結局最後まで自分の正体を明かすような場面はほぼなかった。今のはそういう要素を求める人向けのネタバレ。

https://ncode.syosetu.com/n0806fu/

万魔殿の主〜胡散臭いトレーナーとウマ娘たちは日本を驚かせたい

トレーナーの主人公がチームを作って勝ちまくる。これもミホノブルボンチャートと同じく主人公の設定が好み。丁寧な物腰で、底知れなくて、天才。

万魔殿の主〜胡散臭いトレーナーとウマ娘たちは日本を驚かせたい@休止中、活動報告にて詳細 - ハーメルン

Vtuberってめんどくせえ!

主人公は女性Vしかいない箱から唯一デビューした男性V。些細なことでの炎上を繰り返しつつ、人柄や考えが知れ渡って人気が出ていく。ヒロインである同じ箱の女性Vとの関係性がめちゃくちゃ好き。配信上でも知らず知らずイチャイチャするくらいで、またそのような行動がファンから認められるような仲。

Vtuberってめんどくせえ!(烏丸英) - カクヨム

自作3Dモデルの素材を宣伝するためにVtuberになったら予想外に人気出てしまった

主人公がVtuberではあるが、配信や動画のシーンは少なめでリアルの人間関係が多く描かれる。キャラたちの間に複雑な関係があって色んなニアミスが描かれ、もどかしい思いをした。主人公がひたすら鈍感で何事にも動じない様子なのが好き。

自作3Dモデルの素材を宣伝するためにVtuberになったら予想外に人気出てしまった(下垣) - カクヨム

プレイしていたゲームの能力で転生するやつ

タイトル通りにオリ主がネギま世界に転生する。そうやって得たチート能力をうまく使って、原作キャラを立てつつ自分も盛んに活躍するバランスが心地よかった。

【完結】プレイしていたゲームの能力で転生するやつ - ハーメルン

秋宮ゆららは青を喰む

Vtuber小説。軽い気持ちで配信しているのにあまりに多才すぎて人気が出まくるのが、視聴者の反応も含めニヤニヤできる。同期との関係も好き。

秋宮ゆららは青を喰む - ハーメルン

Vの者!~挨拶はこんばん山月!~

Vtuber小説。主人公とその同期を始めとした同じ事務所の仲間たちが、各章ごとに襲い来る困難を乗り越えていく。誰も彼も才能に溢れていて勢いがあり、日常パートは面白おかしく、シリアスなパートは胸を熱くしながら読めた。三章ラストの吹っ切れ具合とライブシーンが特に好き。

Vの者!~挨拶はこんばん山月!~ - ハーメルン

アラサーがVtuberになった話。

主人公がデビュー時点で自分とは関係ないことで大炎上し、その後も人気がずっと低迷している。しかし鋼のメンタルで何事もなかったかのように淡々と活動を続ける様子が安心して見ていられるし、面白い。64、65話は特別感動的な話で好きなのだが、そこでも心無いコメント等が描写されるあたり徹底している。

アラサーがVtuberになった話。 - ハーメルン

蓬莱山輝夜お嬢様がコナンの世界入りした話

非常に面白い。たった20話足らずでまとまっており、読了後の余韻が心地よかった。事件と解決のパートが大胆にカットされているのもスピード感があり、濃密さに拍車がかかっている。途中いくつも自分好みのシーンがあったのも嬉しい。具体的には、輝夜が超有名人になったのに平気で出歩いて目立ちまくるところ。

蓬莱山輝夜お嬢様がコナンの世界入りした話 - ハーメルン

阿礼狂いに生まれた少年のお話

東方の二次創作。幻想郷の黎明期を生きた主人公の一生を描く。タイトルにも「狂い」と入っているように主人公の精神性の根っこはずっと変わらないのだが、表層は生きていくうち徐々に変化していって、中盤からはそうして形成された気質に惹かれて周囲に集まる人妖との交流が感傷的に描かれることが多かった。終盤になると、ああ主人公の死期が近づいてきたんだなというのが文章から明らかに感じられるようになって、大変名残惜しい思いをしながら読み進めていた。泣ける。

阿礼狂いに生まれた少年のお話 - ハーメルン

天地神明の真祖龍

モンハン二次創作。古龍の祖という最強中の最強の主人公が人間を観察したり、対話したりする描写が好み。

天地神明の真祖龍 - ハーメルン

帝征のヒーローアカデミア

古龍に変化する能力を持った主人公。シンプルに強いし、見た目もかっこいいので体育祭のクライマックスがとても好き。普段ののんびりした態度とのギャップも良かった。

帝征のヒーローアカデミア - ハーメルン

クラップスタナーは2度鳴る。

暗殺教室の二次創作。原作主人公がTS逆行転生する。原作前の部分がかなり好き。本校舎の設定や雰囲気がかなりそれらしく作りこまれていて感心した。その生活の中で逆行したことによる知識・能力の利点を活用していくのは爽快。

クラップスタナーは2度鳴る。 - ハーメルン

銃と私、あるいは触手と暗殺

主人公は元傭兵。原作でいくつかあった潜入や戦闘のシーンでは存分に無双しており、読んでいて楽しかった。そういう場面ばかりではなく、クラスメイトや殺せんせーとの交流を通じて自己の認識が傭兵から中学生に変わっていく過程も描かれて、暗殺者という観点からは弱体化とも言えるものの、納得感があった。

【完結】銃と私、あるいは触手と暗殺 - ハーメルン

俺は竈の女神様

ダンまち二次創作だがエタる直前まで原作前の話なのでほぼオリジナル。特に後半はいくつか別の原作世界に入り込むので、クロスオーバーっぽくもなっている。様々な権能を持つ神様である主人公が、上位存在らしく基本好き勝手している話。強さに裏付けされた自由人っぷりが好み。

俺は竈の女神様 - ハーメルン

デート・ア・ライブ 士道リバーション

原作からヒロインの攻略順序が変わり、さらに時期が大幅に早まっている。そのため一人ひとりとの関係がより深まっていて、特に七罪とのイチャイチャが微笑ましかった。またシーンとしては「狂三スチューデンツ」の高校に入学する部分がピンポイントで自分の好みだった。

デート・ア・ライブ 士道リバーション - ハーメルン

俺の家が幻想郷

タイトル通り、自分の家でミニチュアサイズの東方キャラが生活するという話で、この設定が天才的で好き。主人公の描写がかなり厨二臭いのは読む人を選ぶかもしれない。

俺の家が幻想郷 - ハーメルン

続投

アイドルの世界に転生したようです。

アイマス二次創作。トップアイドルである主人公がその影響力などを駆使して数多のアイドルたちが抱える問題に介入していく話。外伝『Days of Glory!!』はそこから離れて完全オリジナルストーリーが展開され、主人公たちのライブが開催される。本編を忘れた、ただただ楽しい盛り上がりが本当に好き。

アイドルの世界に転生したようです。 - ハーメルン

この〇〇のない世界で

アイマス二次創作。逆行転生した主人公が未来知識とチート能力でアイドルどころかサブカルチャー全体の始祖のようになる話。思い付きで行動したり手当たり次第に事業を立ち上げたりするもどれも大当たりして、現在につながる文化の流れが作られていくのが読んでいて楽しい。

この〇〇のない世界で - ハーメルン

青空よりアイドルへ

アイマスの二次創作。主人公は見た目が貧相なのに歌や踊りのスペックはまさにチート的。そのことが掲示板で話題になっているという描写が好き。

青空よりアイドルへ - ハーメルン

最強カップルのイチャイチャVRMMOライフ

どの章もラストに向けてだんだん話が盛り上がっていって、そのクライマックスに配置されているレイドボス戦が最高に熱い。そういうのを章ごとに何度も楽しめたのが非常に良かった。また、主人公たちは特に配信者ではないのだが、トッププレイヤーらしく活躍する様子が周囲の人間の配信に映ってコメントが盛り上がるという描写が好き。

https://ncode.syosetu.com/n2143dt/

打撃系鬼っ娘が征く配信道!

リアルの身体能力が人間の常識を遥かに超えている主人公がVRMMOの配信をする話。リアルチートで活躍しまくるのが好き。

https://ncode.syosetu.com/n9517fc/

逆行転生したおじさん、性別も逆転したけどバーチャルYouTuberの親分をめざす!

本編は転生してからVtuberの親分と呼ばれるくらいまでの話で、下積み時代の描写が苦しかった分報われたときは嬉しかった。その後から配信アーカイブとして1話完結の話が大量に投稿されていて、どれもシンプルに笑えるという意味の面白さがあってとても好き。

https://ncode.syosetu.com/n3530fy/

輝きたくて

Vtuber小説。逆行転生した主人公がVtuber運営会社を立ち上げて軌道に乗せる。そういう行動力、またやることなすことが型破りで、単に未来知識頼りの人間ではなく十分な才能があったということが周囲の反応から明らかになっていって好きになった。

輝きたくて - ハーメルン

俺は星間国家の悪徳領主!

悪徳領主を目指してそれっぽいことをいろいろするものの、どれも良いように捉えられてしまうという勘違いもの。行動の意図を周囲に勘違いされるときのギミックが手が込んでいて好き。

https://ncode.syosetu.com/n1976ey/

プニキとはじめるリーグ運営 ~野球ゲーム?作って運営します~

高度な技術で、コンピュータ上でできる限りリアルに近づけた野球を再現し、AIの対戦を観戦する「だけ」のゲームを会社を作って運営するという話。スケールの大きな構想を一歩一歩実現していく過程が丁寧に描かれ、とても面白い。よりリアルに近づけるため、野球に関係するありとあらゆることにパラメータを設けたり機械学習による判断を入れているという工夫を解説しているシーンが、読んでいてワクワクする。

https://ncode.syosetu.com/n4212eh/

始まりの魔法使い

竜に転生した主人公が原始人を導いて魔法を体系立てる話。襲い来る困難がどれも重く否応なしに変化を強いられる中で、長命な主人公が昔を懐かしんだりする描写の、人から一歩引いた感じが上位者っぽくて良かった。人口が増えて集落の人間を全員覚えられなくなったという話をしていたのが、人が竜に庇護されるという状態を決定的に離れた感じがして印象深い。また第四章第19話も好き。

始まりの魔法使い(石之宮カント) - カクヨム

滅竜山くんの一生 ~46億歳、全ての生命と魔の祖~

主人公は意識を持つ山で、オリジナル生物を作ったりしつつ生態系の変遷を見守り続ける。そういう「長命な主人公が歴史を作る」という自分のストライクゾーンど真ん中のストーリーが、たった16話で簡潔にまとまっているのは驚き。

https://ncode.syosetu.com/n3617fx/

東方遺骸王

前半は主人公の活躍が、後半は前半で張られていた伏線がことごとく原作の設定に繋がっていく物語の構成的な緻密さが好き。主人公はあまり表舞台に姿を現さないので、大きく動いて自分の持つ力を振るう「遺骸王の激昴」の章がかなり印象に残っている。この展開は大好き。原作キャラが登場しない期間が長いので、ほぼオリジナルだと思って読むべき。

東方遺骸王 - ハーメルン

少女(仮)の生活

主人公が一般人に紛れたり人里離れたところに居を構えたりしながら歴史を眺め続ける話。ただし、強大な力を持っているのに身内の都合を優先するので、いろいろ引っ掻き回すことも多い。その自分本位さに圧倒的な超越者っぽさを感じて好き。

少女(仮)の生活 - ハーメルン

東方狐答録

原作開始の遥か昔からスタートする、いわゆる古代スタートと呼ばれるジャンルの話。東方の古代スタートは、原作キャラが幻想入りする前に元ネタの神妖として活動していた時代に交流したうえでの、幻想入りした後の再会シーンが醍醐味だと思っている。必然的に主人公は長命となり、また長生きするにつれて強大な力を持つようになるため、様々な意味で自分の好みに一致しておりジャンル自体が大好きである。この作品も例に漏れない。第七十二話から少し現代入りする部分が好き。

東方狐答録 - ハーメルン

天才最弱魔物使いは帰還したい ~最強の従者と引き離されて、見知らぬ地に飛ばされました~

最弱の肉体とそれに見合わない強靭な精神を持ち、魔物使いという職業で最強になった主人公が、使役する魔物と引き離されてしまうところから始まる話。そうして戦闘力は皆無になってしまったものの、新天地でも手練手管で基盤を作り、頭の回転だけで存在感を示している様が明らかに異質でかっこいい。ただの設定だけではない、確かにカリスマのある主人公だと感じている。第一章第四十五、四十六話、第二章第三十六話が好き。

https://ncode.syosetu.com/n4224gn/

陰の実力者になりたくて!

勘違いもの。身の回りで起きていることに何も気づいていないのに、実力だけは圧倒的な最強で、いつも見せ場はしっかり決めてしまう主人公が好き。

https://ncode.syosetu.com/n0611em/

最強魔法師の隠遁計画

魔法師の世界ランク1位である主人公が半引退のつもりで身分を隠しつつ学園に入学する話。結局引退できていない。世界最強なのは作中ずっと変わらないけれども、その力を誰にどのように披露するかがだんだん大胆になっていって、そこから得られる爽快感が好き。

https://ncode.syosetu.com/n5606cq/

サイレント・ウィッチ

天才魔術師が正体を隠して学園に潜入する話。魔術に関すること以外はポンコツでコミュニケーションが苦手なため、いろいろ問題に巻き込まれてしまい、解決する過程で学園の生徒たちと仲を深めていく。主人公がいつどのように正体を明かすのかばかり気にしながら読み始めたが、そういう特別な一瞬への期待感を抜きにしても普段のドタバタ騒ぎから面白い。軽めの文章や台詞で気持ち良く読める。

https://ncode.syosetu.com/n8356ga/

うちの脳内コンピューターが俺を勝たせようとしてくる

りゅうおうのおしごと!の二次創作。脳内に将棋AIを飼っていてめちゃくちゃ強いという設定で、その強さを存分に発揮するコンピュータとの対戦シーンがどれも好き。特に「一閃」とその近辺。将棋AIが強いだけで主人公はただの人なんだと思っていたが、実はそうでもないということがはっきりと明らかになるのが良かった。

うちの脳内コンピューターが俺を勝たせようとしてくる - ハーメルン

Game of Vampire

ハリポタの二次創作で、東方とのクロスオーバー+オリジナル主人公。ハリー世代にただオリ主を放り込むのではなく、その親やさらに親の世代から主人公勢力が継続的に魔法界と関わり続けている。そうやって積み重ねる歴史のそれぞれにおいてハリポタ原作の重要キャラと主人公勢力の東方キャラとの間に特別な関係が生まれていて、後々描かれる「ホグワーツ同期のパチュリーと会話するダンブルドア校長」などこれぞ二次創作と言わんばかりのシーンが確かな実感を持つようになった。連綿と続いた流れがついに回収されていくハリー世代はもう最高。シーンとしては「魔法」、「開戦」、「さよなら」が大好き。

Game of Vampire - ハーメルン

比企谷八幡 「・・・もう一度会いたかった」

社会人から逆行した比企谷八幡が、社会人生活で手に入れた知識・技術を振るいつつ高校生活をやり直す話。行事の企画・運営に社会人目線でメスを入れたり、語学力で人脈を築いていくという描写が良い。後者に関しては21話のような展開が非常に好みである。

比企谷八幡 「・・・もう一度会いたかった」 - ハーメルン

週記(2022/06/13-2022/06/19)

06/13(月)

先週は週記を投稿してすぐ布団に入った。午後0時半就寝。

午後4時過ぎ起床。あまりの眠気に体が動かず、5分おきにセットしていた目覚ましに助けられ何とかインターン先定例会の前に布団から這い出た。先週もほとんど何もしていない。昨日の夕方から回していた学習は未だにlossが下がり続けていたので、ログ出力から途中経過を見てそれっぽいことを言ったりしてお茶を濁した。

勉強会はリファクタリングの話。こういうのは宗教的な要素を多分に含んでいて、自分の感覚と合わないものも多い。競プロをやっていて書き捨てのコードばかり触れているからと思っていたが、実は統合開発環境を使わずほぼ素のVimだけでコーディングしているのも問題な気がしてきた。例えば変数・関数の型を自分で覚えておく必要がないというのはかなり便利だろう。そういう機能を駆使することで、プログラムの泥臭い実装からある程度離れて全体的な構造を把握するのもやりやすくなりそう。まあそんな規模のコード群に触れたことがない身でいろいろ言っても仕方ないか。

今週も月曜日は課題に追われる日。一つ目はゲーム理論。今回の教科書の範囲には発展的と注記された内容がたくさん含まれていて、これは課題も大変そうだと身構えていたら、さすがに大変すぎたらしく教科書の演習問題ではなくスライドで定義されたゲームに関する証明が一つだけ課題になっていた。簡単。

二つ目はハードウエア基礎。小さな論理回路が与えられるので、FPGA上に設計せよという問題だった。ルックアップテーブルでn変数関数をシミュレートするのは便利だが、これまで基本的なゲートを組み合わせて頑張っていたのを振り返ると、何というか仰々しすぎる気もする。問題も論理回路を設計するというよりは論理回路の入出力の様子を見て同じ挙動をするように設定するだけで、何が面白いねんという感想に。

三つ目は離散数学。もういい加減分かってきたが、数学科の学生がこの講義を受講して得られるものは単位だけである。学部一年の専門科目でやったことを延々繰り返している。さすが文理問わず受講できる講義なだけはあるぜ……。ただ僕も単位しか求めていないので、実はWin-Winになっている。今日も無難に課題を解いて提出しておいた。来週は休講になるらしい。

四つ目はまたハードウエア基礎。教員3人が持ち回りで担当していて、今週の講義から教員が変わると同時に、課題の提出期限も次週月曜日の23時59分から10時30分に変えられていた。気づけて本当に良かった。念のため今出ている課題をもう終わらせておくことにする。今回は様々な要素から回路の抵抗や容量を求めて云々する問題。レポート提出という形式になったので、答えが正しいか即座にはわからない。変な値になったのが気になる。

終えて午前1時半。日記を書いて午前3時過ぎに布団に入った。

校正と校閲の言葉の違いを知った。これまで日記を読み返して文章を手直しするのを校正と言ってきたが、校閲のほうが正しそう。まあ本当は推敲のほうが良いのだろうが。検索すると「校正」という単語が出現した記事が五つしかなかったので、全部別の表現に直しておいた。

午前4時就寝。

06/14(火)

午前10時前に目を覚ました。まだ寝足りないので二度寝をしようと思いつつ、ついつい布団でスマホを触ってしまう。ABC249で8位を取った時の賞金10000円が届いていた。

先週日曜日(から日付が変わって月曜日)、寝る前に生協に出向いた際に一言カードを確認したら、回答で電話による相談窓口が紹介されていた。せっかく営業時間内に起きているので、ここに電話してみることにする。昼前なのでまだそこまで忙しくもないだろう。納豆の購入制限をなくしてほしいと何度も言ってきたが、自分の考えをもう一度整理すると、結局納豆を一度に2パック購入する方法さえあればよいということが分かったので、これについて聞いてみることにした。

開口一番「レジに2回並べば2パック買えるので正しいのか」と言ったところ、想定しない行動であるが可能との回答を頂いた。なんだ可能なのか。先週僕をレジで止めた担当者の方がルールを勘違いされていたという話も出てきたので、おそらく次からは止められないのだろう。また、ご飯の量が多いなどの理由があればその場で申し出ることで対応してもらえもするらしい。席に食事を置いて離れるのは正直抵抗があるので、こちらを採用したい。

ハーメルンを読んでいた。まず4話でエタっているものをサッと読了。内容の感想はない。そういえば、チャンネル登録者数が1000人なのに普段から同接が500人というのはさすがに無理があると思ったな。しかしどのあたりならリアリティがあるのだろう。知名度は低いけど一部にカルト的なファンを抱える、という状況なら案外近い値を叩き出すのかもしれない。

syosetu.org

比企谷八幡Vtuberになるハーメルンは他にもある。1年以上前に読んで、そのときすでにエタっていたのだが、以来何話か更新があったので改めて読み直していた。やはり面白いし、面白くなりそうという感じもする。

やはり俺がVtuberになるのはまちがっている。 - ハーメルン

昼過ぎからは「輝きたくて」を読み返していた。何度目かわからない。とにかく面白い。

輝きたくて - ハーメルン

午後3時くらいに二度寝に成功。次に起きると午後10時半だった。ICPC模擬国内予選の参加登録が始まっていたので、チームメイトのメールアドレスを聞いてフォームを送信しておいた。

午後11時半からCF #799 div.4。

Dashboard - Codeforces Round #799 (Div. 4) - Codeforces

Aは問題文を読むのに手間取った。aより大か小である個数を答えればよさそうだったので、あとはサンプルを見て合わせ提出。Bは消すべき個数を求めて切り上げ。必ず1個以上残せるので、切り上げたときnを超えることはない。Cは実際にビショップを配置して一致するかチェック。端にないという制約の意味が分からず首を傾げていたが、後からこの制約なら8近傍がXのように埋まっているかチェックするだけでよいのだと気づいた。Dは最初の状態に戻るまでx分経過させるのを繰り返し、それぞれ回文かチェックする。

Eは尺取り。Fは\bmod 10で要素をカウントし、a_i\bmod 10a_j\bmod 10を固定して対応するa_kが存在するかチェックする。Gはa_i\ge 2a_{i+1}なる要素を含まない区間を数える。隣り合う各ペアに関する条件なので添え字の\pm 1がちょっと難しかった。一度b_i=[a_i\ge 2a_{i+1}]と置いて、この数列の連続するk項を考えるほうがやりやすかったか。Hはaを決め打って、それが出現するインデックスを先頭からI_1,I_2,\dotsとしたときにi\le jのもと2(j-i+1)-(I_j-I_i+1)を最大化すればよい。(2j-I_j)-(2i-I_i)+1と変形すれば2i-I_iの累積\minを管理する典型。

24分全完で10位。

今日もマイク音声付きで録画していた。相変わらずボソボソ喋ってしまった部分もあるが、問題文の読解フェーズはあまり黙らないように頑張った。全完まで24分しかないのでほぼ無編集で投稿してしまおう。コンテスト終了までに前後を少しカットしてエンコードYouTubeへのアップまで済ませておき、コンテスト終了後に公開した。サムネはopen hacking phaseが終わってから。

www.youtube.com

今日の夜にしぐれういさんがゲリラ配信をされていたらしい。アーカイブを視聴した。

www.youtube.com

29分21秒時点。気になっていた期間限定商品の販売がすでに終了しているとコメントに嘘をつかれ、すごい顔をするシーン。Live2Dの表情が豊かで可愛らしいですね。

https://www.youtube.com/watch?v=piVNAMMi0_k&t=1761s

日付が変わって06/15からTCB48が始まっていたので参加した。例のごとく日曜日終了なのでここに感想を。

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

6問目はとりあえず根から最も遠い頂点が2^N-1であることがわかるが、もう片方はすぐには決定できない。しかしLCAを全探索すれば十分で、そこからコストを求めるのも毎回O(N)かけてよい。7問目は二分探索して判定はUF。判定にO(N^2\alpha(N))かけてちょっと怖かったが普通に通った。8問目は親の顔より見た拡張dijkstra

9問目は難しい。トポロジカルソートを計算するときについでに何かすることで求まるのかと思って考えるもよくわからない。入次数が0の頂点からの最長距離でグループ分けしたものを提出して思いっきりWAを出した。反例だらけ。30分ほど考えてどうにもならなかったので、各点についてそこに到達可能な点とそこから到達可能な点が合計でN+1個になることを確認する方針に。DAGの到達可能性判定は各頂点でそれぞれ愚直に計算するO(N(N+M))をビット並列にするやつ。事前にトポロジカルソートすることで見るべき頂点を減らし、定数倍にさらに1/2を付けて提出すると4.6secくらいで通った。C++最高!

10問目も難しい。その頂点にたどり着いた時の操作回数\bmod 2を考えて頂点を倍化すると、辺(a,b,c)(a,c)\rightarrow(b,1-c)(b,c)\rightarrow(a,1-c)になり、2N頂点2M辺の有向グラフが得られる。このグラフのすべての辺を通るような道を見つける……わけではない。辺も倍になっているので、そのうち片方ずつさえ通っていればよいというのが問題。まず強連結成分分解して、始点を含む強連結成分からどのように辺を辿っていけばよいか考える。今見ている強連結成分から出る未使用の辺が二本以上あったとき、どれを使うべきか。

実はどれでもよい。そのような辺が2本e_1,e_2とあったとして、それぞれペアになっている辺をe_1',e_2'とおく。例えばe_1を使ったとする。このとき二度とe_2は使えないので、そこから先のどこかで代わりにe_2'を使う必要がある。そうしたら、その間で使った辺をすべてペアのもう片方に置き換え、逆から辿ることができて、e_2からスタートしてe_1'で終わるような道もあることが言える。e_1の始点からe_2'の終点への道がe_2の始点からe_1'の終点への道になってしまうが、問題ない。なぜなら、今e_1の始点とe_2の始点は同じ強連結成分に属していて、その2点を含むループを先ほどのように反転することでe_1'の終点とe_2'の終点を含むループが得られる、つまり2点が同じ強連結成分に属するとわかるからである。

強連結成分間を渡るとき、すでにペアのもう片方を使った辺、つまり使用済みの辺を考えてしまい1WA。上の議論においてe_1\rightarrow e_2'の道とe_2\rightarrow e_1'の道に共通する強連結成分があると、途中で混ざってしまいe_1\rightarrow e_1'を辿ってしまうかもしれないので、ちゃんと一度使った辺を弾く必要がある。逆にこれ以外の場合では壊れない。ペアの片方の辺がどこかの強連結成分に含まれるなら、もう一方の辺も別の、あるいは同じ強連結成分に含まれるから。

9問目が34分1ペナで-27pt、10問目が79分1ペナで-68pt、合計-95pt。10問目はかなりやりごたえがあって面白かった。9問目が本当にわからないので、日曜日深夜のTLを注視したい。

6月中旬~7月中旬の新刊ラノベをチェックして注文した。15冊。06/17発売予定の富士見ファンタジア文庫の新刊が、どれも書籍注文サイトに表示されず、予約できなかった。1件ヒットと書いてあるのに一覧が空だったりして謎。そのうちリアル書店で買うか、機を見て再度注文したい。

午前6時くらいから日記を書き始め、YouTubeを見つつ午前10時に書き終えた。文章量がそれなりにあったので時間がかかったのもまあ納得できる。見ていた動画の一つはこれ↓。先週日曜日に見たカバンチェックと同じく大喜利企画だが、こちらはあまり面白く感じられなかった。8分17秒時点、「酒を呑ませて酔わせて倒す」と言われ即座に「なんで八岐大蛇と同じなんだ」と突っ込めるのはすごいと思う。見ていてびっくりした。

www.youtube.com

https://www.youtube.com/watch?v=WtSwAAOpZl0&t=497s

チャンネル登録者数500人を達成した。しばらく450人手前で停滞していて、そこから3本動画を出して一気に到達。Twitterアカウントの規模が大きめなので、そこから誘導することでインプレッション数が稼げている。

競プロ実況と銘打っているが、決して解説ではなく、ただコンテスト上位に入る人間がどのような速度で解いているのか見せたいという考えで動画を作っている。だから「動画を見て憧れた・モチベが上がった」という感想を見たときは非常に嬉しくなったし、「理解する前に先に進んでいった」という感想に対してはすまないがそういう動画だとしか言えない。幸い僕がTwitterエゴサする範囲では動画は好意的に受け止められているものの、YouTubeというプラットフォーム上で何かフィードバックがあったわけではない。動画とTwitterにおける個人が切り離されているように感じていて、自分の影響が及ばないものの評価を見守っている心境で少し怖い。

学食で食事。ちゃんとレジで宣言して納豆2パックを購入してきた。このメニューを選ぶのはもうこれで何度目かわからないくらいで、今日は合計606円になるはずがなっていないことに気づいて会計漏れを指摘した。

帰宅して布団に横たわり、またYouTubeなりにじさんじ非公式wikiなりで無為に過ごしてしまった。wikiはアンジュ・カトリーナさん。動画は以下の切り抜き。

www.youtube.com

午後1時前に就寝。

06/15(水)

午後4時直前に起床。即座に会議に接続してペアプログラミングを始めた。

序盤はだいぶ頭が回っていなくて反応が鈍かったと思うが、どちらかというと前回(06/03)のペアプログラミングの記憶がほとんど抜けてしまっていたのが問題だった。意識も記憶も回復したので何とか普通に進んでいって、最後、コードが正しく動くか確認しながらしばらく雑談さえ挟み2時間程度で終了。今書いたコードで学習を回し始め、しばらく見守って問題ないことを確かめてから二度寝した。

午前0時半起床。相変わらず学習はちゃんと動いているようでよかった。同じPCでちょっとYouTubeでも見ようかとしたらGPUのメモリがギリギリになったので、慌てて会議アプリだったりSlackだったりを落とした。こういうの、一度起動するとバックグラウンドで一生走り続けるのであまり好きではない。通知を送る以上仕方ないことではあるのだろうが、それは別のPCかスマホから見るので十分なので、毎回手動で落としている。

ハーメルンに気を取られつつ明日、日付が変わったので今日に控えたセミナーの準備をする。もう何回同じページ予習するんだという感じなので、あまり気が乗らなかった。また証明を再現して、今回は万が一にも炎上しないようメモとかではなく丸々書いた紙を用意しておいた。どうせ念入りにやっていたらあまり進まないということが分かっているので、量は控えめ。ハーメルンセミナー準備を体感2対1くらいで行って、午前7時前には切り上げて布団に入った。そこからさらにハーメルンを読んで午前8時就寝。

06/16(木)

午後2時過ぎ起床。火曜日に投稿したCF #799の実況動画だが、順位が確定していたのでサムネイルを作って設定した。上に二つあった灰色・無色のアカウントが両方消えて8位に上がっていた。

ちょっと遅めの時間に出発し、生協でパンやおにぎりを買って教室へ。おにぎりだけ食べてすぐセミナー開始。今日は僕の発表だと思っていたが、実際はもう一人と時間を半々に分け合う予定だったらしく、さらにその人の発表が長引いて今日は聞いているだけになった。

岡目八目とはよく言ったもので、証明の簡単そうな別方針だったり黒板に書かれていることの反例だったりがいくつか思い浮かんで指摘したりした。そういうことをする立場は気楽だが、指摘される側はたまったものではないのだろうなとも思う。自分も昔黒板発表で炎上して頭が真っ白になった経験がある。先生からもいろいろ指摘を受けていて、今日はとにかく大変そうだった。これについては途中から先生が発表者の発言を遮りがちだったのも問題に思える。

ただ自分自身をネガティブに言い続けるのは、聞いていてこちらの気も滅入ってしまう……自分で自分を信じられなくなったら終わりですよ。

学食で一緒に食事し、別れて帰宅。ふぁぼん氏が氏の食生活についてブログを書かれていた。僕の「ペペロンチーノの作り方」のオマージュらしい。ところで、オマージュとリスペクトは大体同じ意味のようだが、自分で自分のブログ記事がリスペクトされていると言うのは語感からして尊大すぎるので、ここではオマージュという語彙を選択した。

yuyusuki.hatenablog.com

kotatsugame.hatenablog.com

そもそもライバルとして見定めている人はいないのだった。さらに競技プログラミングの問題もあまり解かなくなってしまった……。

シャワーを浴びて午後8時くらいには布団に入った。少しハーメルンを読んで午後9時くらいに仮眠に入り、午後11時過ぎに何とか起床した。午後11時半からCF #800 div.1。

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

Aはi\rightarrow i+1の操作とi+1\rightarrow iの操作が同じ回数だけ行われるので、それによる影響を前または後ろから順に見ることで操作回数を決定していける。僕は後ろから見た。操作回数が負になる場合と、途中で0になる場合、つじつまが合わない場合がアウト。Bは葉から順に自分の子に流せる値の最大値を求め、それがl未満ならrに、rより大でもrにするということを繰り返すのが最適。l未満からrにするときに操作回数が1増える。

Cはよくわからない。単純にdpしようとすると、uに対してu\rightarrow vなる辺を見てdp_v+1を求め、各値に対してそれより大きな値に繋がっていた辺をすべて削除するときのコストを足したものの最小値がdp_uになる。ただしループがあるのが問題。単に頂点1からDFSして、ループを検出した場合dpの値を\inftyにするようなコードを書いたら落ちた。そこで逆に頂点nからdijkstraのように求めることを考えた。dp_{v_0}が決定したとき、u\rightarrow v_0に対してdp_uを、dp_{v_0}+1に「まだ使っていないu\rightarrow vの本数」を足したもので更新できる。なぜなら、今dijkstraをしているので、まだ使っていないu\rightarrow vについてdp_v\ge dp_{v_0}が成り立ち、足した値が先ほどの「それより大きな値に繋がっていた辺をすべて削除するときのコスト」に相当するからである。これで通った。未だに最初のコードの何が悪かったのかわかっていない。

ここまで26分。残り1時間半はDで詰まって椅子を温めていた。まったく良い性質が見つからない。実験などを経て先頭から増加列・減少列を適当な規則に従って貪欲に更新することで判定は行えるとわかったので、その二つの列を上手いこと更新して尺取りのようなことができないか考え、できずに終了した。3完速解きで77位、レートは2906→2875(-31)。

火曜日にラノベを予約した時表示されなかった商品が表示されるようになっていたので、改めて注文した。7冊。

またしばらくYouTubeを見ていた。以下の動画。以前剣持刀也さんの話術について日記に書いたことがあったが、やはり屁理屈が上手い人として認識されていたらしい。また7分24秒時点の「天変地異」は遊戯王のカード名の意味で取ると話が繋がりそう。お互いデッキを逆さにしてプレイするという大胆なカード。

www.youtube.com

https://youtu.be/ZN1MBVAWqPw?t=444

ラストでスタッフを煙に巻くシーンがあって、急に入社日マウントを取り始めるのが本当に好き。話題とは一切関係ないことをすぐに持ち出せる発想力がすごい。22分27秒時点。 https://www.youtube.com/watch?v=KwxIJYdRl3s&t=1347s

週記(2022/06/06-2022/06/12) - kotatsugameの日記

ハーメルンを1作読了。「この手のひらで踊れたのなら」。超然とした主人公が好み。しかしどうやら体を勝手に操られていたらしいということが明らかになってきて、かなり不穏な気配が漂っている。

syosetu.org

GCJ Tシャツに関するメールが届いていたので注文し、それから日記を書き始めた。かなり長い時間をハーメルンに吸い取られてしまい、この部分まで書き終わったのが午前10時。メールを見たら、ABC253の賞金が届いていた。この回は全体3位、日本人2位で、優秀賞と基礎科学研究奨励賞(数学専攻のため)で合計18万円。当然これまでもらった額では一番大きい。正直現実味がない。

いったん布団に入るもあまり眠れる気がしない。眠気はあるが目が冴えている。再度起きて少しおすすめのなろう小説まとめを書き進めた後、午後1時前後に一瞬出かけた。学食で食事し、購買でラノベや菓子パンを購入し、原付に給油してきた。帰宅して布団に入り、ハーメルンYouTubeで時間を溶かして午後4時就寝。

www.youtube.com

見ていた動画はこれ↑。最初、花畑チャイカさんの演技のみの切り抜きを見て、とんでもなく面白かったので他の人のも全部見た。結局彼のものが一番面白く感じられたので、それについては字幕が付いた切り抜き動画のほうを下に貼っておこう。他の人のもそれぞれで良かった。社築さんの「俺がついてるだろ」は自分でも知っているくらいの、音ゲーマーの間では有名なネタ。つまり内輪ノリの一種に感じられて、それを知らないだろう他のVtuberの反応が聞いていて辛かった。変な笑いが出てきたので、そういう面白さもあったということか。そもそも面白さを競う企画ではないのだが……。

www.youtube.com

06/17(金)

午後11時過ぎ起床。ICPCのチームが組まれていて、登録した情報が足りないというエラーが出ていた。Companyの欄を、特に必要とも書かれていないのに埋めなければならないらしい。Noneと書いておいた。

ブックマークしている小説の作者さんが別作品を書かれたそうなので、読んだ。5話完結でさっくり。特に好きではなかった。ノクターンノベルズなのでリンク先R18。

https://novel18.syosetu.com/n6221hr/

そのあとは朝までずっとおすすめのなろう小説まとめを書き進めていた。ちょっと読み返してみたり、読了当時の日記を見たりして何とかコメントを捻り出していたので、数時間かけて10作品分しか書き進められなかった。かなりの難事業。今日は読み返しのつもりで熱中するようなことはなかったが、その代わりうっかり捜索掲示板を漁り始めたりランキングを見たりして、最終的には別のハーメルンを読み進めつつ書く状態になっていた。

午前9時半就寝。

06/18(土)

午後3時前に目を覚ました。ハーメルンを読みつつ冷凍弁当の配達を待つ。

まず1作読了。「貴方は中央トレセン学園から追放されることを希望しています。」。

syosetu.org

悪印象を与えようとして取った行動が好意的に受け止められてしまう勘違いもの。トレーナーが主人公のウマ娘二次創作としては、口調が乱暴だったのが印象的。たいていは丁寧であるか、そこまでいかずとも愛想がないだけのことが多かったはず。話の設定上自然とは言え、正直良い気分はしなかった。

話は、主人公視点で数話進んだ後、そこで発生した勘違いの経緯を周囲の人物視点で1話描くことによって説明する、というのを繰り返す構造になっている。自分の知る範囲では目新しくて良かった。個人的には周囲の人物からの評価をもっとネットリ記述するようなものが好みだが、こうやってテンポよく新しい勘違いが発生し続けるのも読みやすくてよかった。

午後4時半ごろに弁当を受け取り、さらにハーメルンを読み続けてもう1作読了。「追放系お嬢様」。この2作は最近並行して読み進めていて、ちょうど同時期に最新話まで追いついたということ。

syosetu.org

「輝きたくて」の作者の新作。勘違いもの。前作でも被虐願望のあるTS転生者を描いていたが、今回の性的嗜好はもっと悪化していた。正直ついていけない。勘違いの内容についても今のところ特に印象に残ったものはない。ただ、なぜ勘違いされてしまうのかの理由が明らかにされたときは、なるほどと思った。前作では途中から主人公に対する評価が自分の中で変わった記憶があるので、今作もそんな感じの展開があることを願う。

午後5時半ごろに二度寝。そこからなかなか起きられず、午後8時半に何とか布団から出た。食事してすぐABC256。

Tokio Marine & Nichido Fire Insurance Programming Contest 2022(AtCoder Beginner Contest 256) - AtCoder

Aはやるだけ。dcの4Bを9秒時点で提出してFAを逃し、直後にbcの2Bが存在することに気づいた。もうダメダメ。そこからはC++。Bは何を言っているのかよくわからなかったので、言われた通りに書いた。Cは左上2\times 2を全探索。DはL_iでソートして先頭からマージできるならしていく。Eはi\rightarrow X_iと辿っていくとループに辿り着くので、それぞれのループ内で最も小さいCだけ答えに足せばよい。同じループを2回以上数えないように注意。

Fは面倒。Cを等差数列を区間加算できる遅延セグメント木で管理して、区間和でDを求めた。GはN角形の頂点を一周しつつ、頂点の色と各辺上にある白い石の個数を持つdpを考えて、後者は互いに関係がないことに気づき、前者だけで行列累乗した。ただしこの考察の流れから、2\times 2行列の各要素を長さD+2のベクトルにして、ベクトル同士の加算乗算を要素ごとに行うような方針を取ってしまい、実装にちょっと苦労した。各辺上の白い石の個数を先に決め打ったほうが明らかに楽。

Exは同じ値になった区間をマージすればあまり種類数が増えなさそう(未証明)だったので、それをmapを使って実装する。ただし区間和の取得は難しいので、区間setと区間和取得が行える遅延セグメント木も用意して、適宜書き換えた。3125ms。

ノーペナ全完で16位。Eの解説を読んで、これまでfunctional graphという言葉を誤用していたことに気づいた。正しくは出次数が1の有向グラフであるようだが、自分は加えて入次数も1であるようなものだけそう呼んでいた。日記におけるこれの出現を調べると、全部順列をグラフに直したときの表現だった。入次数が1であることに着目しないとグラフ全体がいくつかのループに分割されることが言えないので、functional graphだからループに分けて云々みたいな説明が意味をなさなくなってしまう。では入次数も1のグラフはどう呼べばよいのか?適切な表現を知らず直すのが面倒なので、放置。

午後11時半からCF #801 div.2に出た。レジったページを開きっぱなしにしていたら時計の誤差が積み重なり、ページ上のカウントダウンが残り10秒を切ったぐらいでリロードしたらもうコンテストが始まっていてびっくりした。

Dashboard - Codeforces Round #801 (Div. 2) and EPIC Institute of Technology Round - Codeforces

Aは最大値のマスを必ず含むような縦幅・横幅を考える。最大値がA_{i_mj_m}だったとすると答えは\max(i_m,n-i_m+1)\times\max(j_m,m-j_m+1)になる。Bはnが奇数ならa_10にすることで先手勝ち、そうでない場合は二人とも取る山が同じなので、1個ずつ取っていったとき初めてなくなる山、つまりaの最小値と等しい最も先頭の山がどちらのプレイヤーに対応するか調べる。何を考えたか総和の大小を比較して1WA。Cはbitsetでdp。

D1は、一つ必ず聞く頂点を決め、そこを根とした根付き木を考える。子を二つ以上持つ頂点について、その子らはそれより下の頂点を聞かないと区別できない。よって各頂点に対し、部分木の頂点を全部区別するために必要な聞く頂点の個数を求める木dpが考えられる。dpの値がちょうど0の子、つまりそれ以下の頂点を一切聞かなくてよいような子、が二つ以上あった場合にそのうち一つ以外を追加で聞く必要がある。そしてこのdpは、各頂点の値が隣接する頂点の値だけから計算できるので、全方位木dpに書き換えられる。

先にD2に提出し、通るのを確認してD1にも出した。D2の点数のほうが低いのでこうすべきだと考えたが、冷静になって考えてみると、間違っていた場合のリサブのペナが定数であるのに対し、時間による点数の減衰は元の点数に比例するので、ちゃんとD1から出したほうが良かったらしい。何なら全方位木dpに書き換えるのに手間取ったので、O(n^2)が書けた時点でD1を提出するべきだった。

Eはちょっと面白い。二人が置いたドミノをマスを結ぶ辺だと思うと、全体はいくつかの長さ4以上の偶閉路に分けられる。ここでドミノをマスではなく値を結ぶ辺だと思い、各辺を2回ずつ使っていくつかの長さ4以上の偶閉路に分割できれば、縦2マスのマス目に置くだけで盤面と二人のドミノの配置を決定できる。ただし片方の人だけが同じドミノを2回使ってはいけないことに注意。これで偶閉路にうまく分割する問題になった。

ひとまず、連結成分ごとにすべての辺を2回ずつ使って一つの偶閉路が構築できる。具体的には、適当な全域木を取って辺属性オイラーツアーのように並べ、余った辺はどちらかの端点にいる際に往復すればよい。このようにして作った偶閉路(を適当な位置で切り開いた列)について、それぞれ二本ずつ含まれる同じ辺の出現位置の偶奇は異なるため、そこから決めたドミノの配置で片方の人だけが同じドミノを2回使うことはない。長さに関する条件は、辺を一本しか含まないような連結成分でなければ満たされる。dfs木を取って実装した。多重辺や自己ループの扱いが難しい。

あとは復元。二人のドミノの配置を作るのがちょっと面倒だった。まあジャッジのためには仕方ないか。うっかり1ペナ付けつつ全完、システスも全部通って11位。

ABCのコードゴルフをする。Aは速度で負け。Bは全完後に考えると後ろからの累積和が4以上であるような要素の個数だと分かったので、dcで実装して17B解を作ったものの、まったく同じコードがコンテスト開始すぐに提出されていてひっくり返った。朝方になって-1Bできた。CはAWK2\times 2マスの全探索の最中にうまくループの範囲を調節することで、確認すべき条件を減らしている。DもAWK。imos法。EはRuby。すでに通った頂点を検出するまでfunctional graphをたどり続け、今のループで通った頂点が見つかったらその部分が初めて見るループなので、答えを求めて足す。以降は手付かず。

日記を書き、しばらくYouTubeを見てから布団に入った。実は布団に入ってからもYouTubeを見ていた。午前9時半就寝。

06/19(日)

午後0時半くらいにうっかり目を覚ましてしまった。

今日のOpenCupが開催されるのかわからないとツイートしたところ、Telegramで情報が得られると教えてもらった。というかOpenCupに招待されたときにちゃんとそのリンクが貼られた文章が共有されていたようだ。全然見ていなかった。

そこを見て、この時間になっても特に更新がないことを確認。今日は代理コンテストになりそう。午後9時からのARCに被せないため午後4時から5hで参加しませんかとチームメイトに聞いてみると、了承・同意が得られたので、そうなった。というかこの時間に連絡つくのは感動。コンテスト直前まで起きられず寝起きで5hに突入するのって僕だけらしいです。

明らかに寝足りないので午後4時直前まで二度寝するぞと思って再度布団に横たわるも、なぜか眠れない。午後3時くらいまで布団で身悶えして、仕方なく起き上がった。今日は睡眠時間3時間で5h+2h+3hに挑む。

まず、午後4時からOpenCup代理コンテスト。コンテストタイトルはPTZ 2022 Winter Day 6 (ICPC Camp Day 1)であった。チームでGHICAの5完で、担当したのはAだけ。それも未証明で通したので、解法をあまり真面目に書く気がない。

06/21追記:https://www.acmicpc.net/category/detail/3056

頂点数Nで辺数が2NK本以上の無向グラフから適当な頂点集合を重ならないように二つ取り出して、それぞれの集合のすべての頂点がもう一方の頂点集合に隣接する頂点をK+1個以上持つようにせよという問題。Diestel Graph TheoryのTheorem 1.4.3が「平均次数4K以上のグラフは点連結度がK+1以上の部分グラフを持つ」という主張なので、この証明を追えば解けると思って結構長い間粘着した。結局点連結度は何の役にも立たなくて、次数が2K以下の頂点を削除していくことで次数2K+1以上の頂点のみからなる2K+2頂点以上の部分グラフが得られることだけが分かった。

しかしこれは当然の話。次数が2K以下の頂点を削除しているのだから最小次数が2K+1以上になるのは当たり前、次数が2K+1の頂点が存在すればそれ自身を含め頂点数が2K+2個以上になるのも当たり前。頂点1個と辺を高々2K個組にして削除しているので、常に平均次数が上がり続けるのだから、グラフは空にならない。今年のGCJ R3では平均次数が小さい状態が保たれていたが、それとは逆向きの評価を行っている。見覚えのある議論だと思っていたらProp 1.2.2に全く同じことが書かれていた。

以上がとりあえず正しいとわかっていること。あとは、残っているグラフの頂点を二つに分割して隣接する頂点の個数に関する条件を満たせばよい。頂点集合をABとして、最初全部Bに入れておいてどんどんAに移すという操作を行った。操作後にBの各頂点がそれぞれAに隣接する頂点をK+1個以上持つようにはできたので、Aでも同様の条件を同時に満たすためABを入れ替えて同じことを何度も繰り返すというコードを書いたら通った。

残りの問題は何もわからない。Jの考察に参加して、チームメイトがそれっぽい解法の実装に入ってからは完全に集中力が切れていた。さすがに数時間椅子を温め続けると厳しい気持ちになる。

直後、午後9時からARC142。

AtCoder Regular Contest 142 - AtCoder

AはKを反転しても小さくならないことを確認し、N以下の範囲内でKまたはそれを反転したものの末尾に0を加え続け、カウントする。Kが回文である場合に注意。Bは連番で埋めた後、奇数行→偶数行の順で並べるだけでよい。

Cは3\le u\le Nに対してd_{1,u}+d_{2,u}を求め、これがkであるようなuの個数がちょうどk-1個となる最小のkがだいたい答え。ただしd_{1,2}=1である場合が問題。このとき、全てのuに対して|d_{1,u}-d_{2,u}|=1なので、まずこれをチェックしておく。この判定に通るのにd_{1,2}\gt 1となる場合は、N=41-3-4-2のような並びをしている場合しかないと思って、これを特別扱いしたら通った。出力形式ミスで1ペナ、コーナーケースの処理をミスして1ペナ。

Dは面倒。良い操作はそれを戻すこともできるので、操作の度に初期状態と1回操作後の状態を繰り返すかチェックすればよい。操作の際に移動した駒を元に辺を向き付けると、互いに重ならない長さ2以上の有向パスがいくつかできて、各有向パスではもともと終点以外のすべての頂点に駒があったことになる。逆に、木をこのような有向パスに分解して今述べたように駒を置くことで、良い操作が可能な駒の置き方を全部生成できる。

あとは操作を2回繰り返したときに元に戻る、つまり2回目の操作に対応する有向パスが必ず1回目を反転したものになるという条件について。まず、駒がない頂点が隣接してはならないので、パスは木の頂点すべてをカバーしている必要がある。さらにパス同士の位置関係について丁寧に考えると、パスの内部の点に別のパスの端点が隣接してはならないこと、パスの始点が隣接しないこと、パスの終点が隣接しないことを満たしていれば良さそうだと分かった。

木dpをする。部分木について、その内部を条件を満たすように有向パスに分解する方法を数え上げる。これを根の状態を解説通り五つに分けてそれぞれで持ち、気合いで遷移を書く。細かい説明は放棄する。子全部を見るループを7回書いたが定数倍的には余裕だった。精神的には全然余裕ではない。しばらくの間上に挙げた三条件のうち一番目を見落としており、サンプル3だけが全然合わずかなり絶望した。何とか合わせて提出し、WAで、端点の隣接関係を勘違いしていたところを書き直してAC。

残り20分くらいでEへ。フローだと決め打ってグラフをエスパーしようとし、失敗。諦めモードになりつつしばらく考察していた。魔法使いiについて、その強さa_iL_i=b_i以上であるか、またはR_i=\max_{\exists(i,y)}b_y(ペア(i,y)が存在するようなyを渡る最大値)以上である必要がある。とりあえずこのどちらかを満たすまで強さを増やしておく。さて、この状態でまだ良いペアになっていない二人の魔法使いについて、片方はL\le a\lt Rであり、もう片方はL\gt a\ge Rである。よってこのようなペアに辺を張ると、出来上がったグラフは二部グラフになる。

適当に塗り分けて連結成分ごとにどちらかの色だけ条件を満たすように増やすとよいのではないかと思い、実装してラスト1分で投げて当然のように落ちた。後からケースを確認すると、prefixが05_maximalのケースだけ全部落ちていて面白かった。まあそれが30ケースあるので惜しくもなんともない。

4完。やはりDから難しかったようで、26位になっていた。Cは実は嘘解法だった。N\gt 4の場合でも上で無理やり弾いたのと同様のケースが発生してしまう。

午後11時半からCodeChef。June Lunchtime 2022 div.1。

https://www.codechef.com/LTIME109A

1問目の問題IDはもともとLOSTARRAYだった。開いて、10分弱かけてコーディングまで済ませたのだが、提出ページが開けなかった。慌ててコンテストトップに戻りページをリロードしたところ問題が消え去っていた。キレそう。ただ他の問題のACがほとんど出ておらず、みんな同じ現象に遭遇していたことが伺えたので、そこだけは救いだった。とりあえずツイートでキレ散らかしておく。

後になってLOSTARRAY_というIDの問題が追加され、コンテストが10分延長された。コンテスト中に問題が消えたり増えたりするdiv.1 rated(結局ratedだった!)って景気がよすぎるだろ。頭お花畑か?絶対語り継いでやるからな。どうやら、古い問題とIDが被ってしまって、意図せずそちらの問題が表示されてしまっていたようだ。

以下解いた順に。MAXCYCSHIFTは累積XORの(多重)集合の変化が「要素を一つ削除する」「削除した要素を全体にXORする」「新しく一つ値を追加する」の3手で書ける。よって集合全体にXORされた値を持てば削除と追加だけで再現できる。XORXORSUMは難しい。最上位桁から見るのは失敗。最下位桁から見るのがよい。最下位桁が同じ数同士で組にする必要があって、0である数は全部2で割って再帰的に解く。1である数はその次の桁が0のものと1のものでペアにする必要があって、2種類に分けた後全部4で割り、「二つの集合から一つずつ選んでペアにする場合の数」を求める関数を用意して解く。この関数もまた再帰関数として実装できる。

LOSTARRAY_はもともと1問目に置かれていただけあって簡単。Nが奇数のときはA全体のXORが決定して、偶数の時はそもそもどれを全体のXORだと思っても適切なAが復元できる。XORDETECTIVEは、まずX=0を聞いてA\oplus Bを手に入れ、この値で立っている最上位ビットの割り当てを決定する。そこから上下に広がるように一桁ずつ決めればよい。下のほうは、AでもBでも立っていないビットをXで埋めることで、Xによる繰り上がりをA\oplus Bで立っているビットまで影響させることで区別できる。上のほうも考え方は同じ。問題文をよく読んでおらず、TQをそれぞれ読み損ねて2WA。愚か。

あとは部分点。MINXORSEGはBinary Trieを必要なところだけ作るセグ木だと思って、更新する度に現在の集合に対して問題を解いた値を求めておいた。これでMo's Algorithmを実装し、小課題3までの50点。手元のランダムケースで20秒弱かかっていて満点は絶望的だが、なぜかしばらく粘着していた。16秒くらいにはなった。インデックスを持っていた部分をポインタにしたら、そのポインタが差す先が実はvectorの要素で、メモリ再確保が発生し値が壊れてしまったりした。最初に十分な量reserveしておくことで対処。

INC0XORはbitDP。小課題2までは自明、と言いつつ2^7の桁まで繰り上げる必要があるケースで引っかかった。小課題3、4は逆に各桁についてどの要素を繰り上げるか全探索すると思ったのだが、答えが合わない。残り時間が少なく、何が間違っているかもわからないままコンテストが終了した。

480点で13位、レートは2761→2730(-31)。XORXORSUMは最下位桁から見ると条件を満たす相方の数がただ一つに決定するらしい。言われて考えてみれば確かにそう。最上位桁から見て列を分割していく方法を最初に考察し、最後までそれに引きずられていた。

消えてしまったLOSTARRAYのほうもコードは完成していたので通しておいた。区間に対しbitwise ANDを行う更新で条件を満たし、区間bitwise ORを求めることでちゃんと条件が達成されているかチェックできる。適当に遅延セグ木で書けそうだったが、念のためビットごとに累積和を取ったりする方法で実装した。

https://www.codechef.com/viewsolution/67201656

TCB48が終了していた。全完優勝。そもそも全完が二人しかいなかった。9完の人とあまり点差がなかったので危ないところだった。

ARCのコードゴルフ。Aは適当にPerlで書いておいた。Bはなんと2,1,4,3,\dotsと出力するだけで通る。ただしNが奇数のときN^2N^2+1を交換しようとしてはならないことに注意。dcで21Bで書けてしまった。N\times Nに整形する必要がないのはいつものことだが、それにしても行・列を完全に無視できるうえ、ここまで単純になるのはびっくり。各行について値の大きさがジグザグになっていればよさそうという考えから試した構築方法だった。残りは手付かず。

午前4時くらいから日記を書き始めたが、どうにも眠い。明日はインターン先定例会の前にもミーティングが入っていることだし、無理せず寝てしまうことにした。午前6時就寝。

週記(2022/06/06-2022/06/12)

06/06(月)

先週の週記を投稿してから。午前9時過ぎに布団に入って、ちゃんと7時間くらい眠れるな~と思っていたのに、うっかりにじさんじ非公式wikiを読みふけってしまい結局就寝したのは午前11時半だった。ちなみにベルモンド・バンデラスさんと社築さんの記事を読んでいた。

午後4時起床。回していた学習の記録をグラフにプロットするなど準備をして、インターン先の定例会に臨んだ。先週はバリバリ進捗を産んだのでかなり気が軽い。ノリノリで発表した。

勉強会は先週日曜日に終了したAHC011の話。僕は結局初日に1Bの解を提出しただけ(しかも時間差で最短を取れていない)だったが、順を追って説明されることで何となくの全容を把握することはできた。印象的だったのは、「目標の全域木を作ってスライドパズルを解く」という方針を得る方法。初日のmaspyさんのスコアを1ケース当たりに直してみると、スコア関数の定義から全域木を作るのが前提の戦いだとわかるらしい。またこれはスライドパズルという問題の性質からも必要で、何故かというと目標の盤面とどれくらい離れているかでしか現在の盤面を評価できないから。なるほど確かに、解いている途中で得られた木の大きさになんて微塵の価値もない。

今日の夕方あたりにニコニコ動画の「おとわっか」が削除されてしまったらしい。ちょくちょく再生していたので寂しい気持ちになった。諸行無常。最初はヤマダ電機からのコネクトパートばっかり注目していたのだが、さすがにMADに失礼だと思って全編通して視聴するのを繰り返した結果、その前のダダダダ天使パートが好きになってきていた。

【合作】おとわっか - ニコニコ動画

眠気をこらえ、今日が期限の課題2つと明日期限の課題を1つ倒す。まず最初はゲーム理論。手書きだと読みづらいからWordかTeXで書けというコメントが出ていて、仕方なくWordで。思ったより戦略系ゲームの表を作るのが簡単だったのは良かった。ゲーム木を書けと言われるとまた困ってしまうが、それ以外だと圧倒的にWordのほうが良いな。そもそも図表を作成するのが面倒という先入観から手書きを好んでいたのだった。

次にハードウエア基礎論。ちょっとよくわからなくなってきた頃合いだな、と思いつつ講義スライドを眺めて、課題を開いたら特にスライドに言及のなかった計算問題ばかり並んでおり大変びっくりした。スライドではなく講義動画を視聴したらまた違うのだろうか。何とかそれっぽいことはできそうだったので、上手く空気を読んで手を動かし、何とか今回も全問正解で終えられた。Googleフォームを利用した課題なので点数が即座にわかる。

完全に集中が切れてしばらくYouTube。やはり人が喜びを爆発させているシーンは良い。音ゲーの話題ということもあって、この配信が当時のトレンドに乗っていたのを見聞きした気がする。記憶の捏造か?当時何やってたんだろうと思って日記を読み返したら、ラノベを3冊読んだ日らしかった。最近さっぱり読めてないな……。

www.youtube.com

本当はサークルの運営とかICPCに関する記録のまとめとかしなければならないことが確実にあったのだが、ラノベを3冊も読んだらたいていのことはどうでもよくなる。積読を減らしたので、今日何もしていないわけではないと自分で信じられるのが大きい。

週記(2020/11/09-2020/11/15) - kotatsugameの日記

日付が変わってから火曜日期限の課題、離散数学のものを提出した。同値関係であることの証明を3つの性質それぞれで書くのが少し面倒だった。

ありえないくらい眠い。すぐ布団に入って、少しハーメルンを読んで午前1時半に就寝。

06/07(火)

なかなかスッキリとした目覚めで、これは睡眠負債もかなり返済できたかな?と思いつつ時計を見たら午前6時半だった。明らかに睡眠時間が足りていないので一刻も早く二度寝しなければならない。なのにやたら寝起きが良く、全然眠れなかった。

しばらくYouTubeを見て、ハーメルンの更新をいくつか読んで、なろうを読んで、午後2時になってようやく二度寝。次に起きたのは午後8時だった。

またずっとなろうを読み続けて、午後11時半からCF #797 div.3。ところで最近、CFのURLをブログに埋め込むときにタイトルを表示する機能がうまく動かなくて悲しい。以前までだったら以下のリンク文字列は「Dashboard - Codeforces Round #797 (Div. 3) - Codeforces」のようになっていたはずだ。自分で書くこともできるが、面倒。

https://codeforces.com/contest/1690

Aは出力がh_2,h_1,h_3の順番であることに気付くのが難しい。Bは\max_i a_i-b_i回だけ操作して達成できているかチェック。各iについて、a_i-b_i回ちょうど操作するべきか、またはそれ以上の回数なら何でもよいか決まるため、どちらにしろその\maxをチェックすれば事足りる。Cは直前の仕事が終わった時間を記録して前から見る。Dはさすがに自明。Eは微妙に難しくて、a_i\leftarrow a_i\bmod kとすると、ペアであって和がk以上となるものの個数を最大化する問題になる。ソートしてa_iが大きいほうから見て、必要最低限の値とペアにしていくのを繰り返すのが最適。

Fはいつもの置換の周期を求めるのを、ループの長さの代わりに文字列の周期を使って計算する問題。文字列の周期については長さの約数を全探索したので、最悪ケースでもO(n\sqrt n)になっているはず。この問題、マルチテストケースのくせして\sum nに制約がない。このことにコンテスト後になって気づき冷や汗をかいた。Gは累積\minが更新されるインデックスをsetで持って追加・削除を繰り返す。各クエリはまずkがsetに入るかチェックして、入るならその後ろの要素をどこまで削除するべきか順に試していく。

全完時点で3位、その後ペナ差で抜かれて6位に落ち着いた。

PCのSSDが画面キャプチャのストックで圧迫されてきたので、悪い成績だった回やAtCoder以外のコンテストに参加した時のキャプチャを削除した。とりあえず70GBほど空けたので一安心。正直、ある程度昔のものは全部削除しても良さそうな気がしている。古いものよりは新しいものを編集するべきであるから。ああ、前にA問題のACシーンだけを集めた動画というのを考えたのを思い出した。これを作るとしたら、今日いくつか完全削除したのは失敗だったかもな。

先ほどのCFは、初めての試みとして音声も拾いつつキャプチャしていた。コンテスト開始まで少しのカットと、一部映ってはいけないものにぼかしを入れるだけの編集をサッと済ませてエンコードし、投稿。いわゆる生声実況のつもりだったが、特に問題文を翻訳して読み上げたわけでもなし、ただただ僕がボヤいているだけの動画になってしまった。これも実況であると強弁している。順位は確定後にサムネに入れておきたい。open hacking phaseで僕のコードがHackされたらどうしよう……。

www.youtube.com

YouTubeにじさんじの公式番組に熱中。にじさんじ無人島シリーズを3本一気に見てしまった。演者を一切映していないのに普通に違和感なくバラエティできているのはすごい。ところどころでしか3Dモデルが使われていないから、おそらく動きだけスタジオで別撮りしたのだろう。それ以外の部分はなんと声だけで面白い動画が構成されている。サバイバルもガチ。ガチでやっているのに動画に映った部分は演者の影の映り込みもないのが本当にすごい。

www.youtube.com

しかしこうやってにじさんじの公式番組に熱中するのと、地上波のテレビ番組に熱中するのには全く違いがないように思える。僕がテレビをあまり見ない人間だったのは、つまるところ出演者に興味がなかっただけの話だったらしい。大学生になったとき、下宿先にテレビを置かないことで今後もテレビ番組から身を遠ざけようとしていたのに、今こうやってYouTubeで漁りまくるようになってしまい台無し。しかし一片の悔いなし。

朝方から日記を書き始めた。月・火のぶん。結構時間を使い、午前9時半就寝。

06/08(水)

午後4時半起床。しばらくPCを触ったりして、午後6時に家を出発した。今日はゲーセンに行く。空模様が怪しいので自転車は使えない。

家と地下鉄駅とゲーセンの位置関係を考えたとき、地下鉄に乗るのと歩き通して行くので時間的にあまり違いがないのでは?と考え、試しに歩いてみた。実際、地下鉄のタイミング次第とはいえ平均的には同じくらいの時間でゲーセンに到着できそう。今日は途中で寄り道して油そばを食べ、ATMでお金を下ろした。

午後7時から閉店までゲーセン。新曲を埋めた後、14+の新規AJを狙っていた。今日は3曲。

前半が苦手。特にフリック混じりのスライドとタップをそれぞれ別の手で処理するところが全然安定しなかった。焦ってリズムがうまく取れない。後半はおおむね上手で、一番最後、高速の交互から切り替わった4鍵の最後だけ結構失敗しがちという感じ。確か2敗。前半で失敗することが多くなり捨てゲーが連続して、今日は止め時かと思っていた頃合いでかみ合った。しかも最高精度。ラストのホールド・スライドの右の始点で2個出したのがちょっと残念か。まあそれがなくても9950には届いていないので、気にしてもしょうがないと割り切れている。99AJというだけで十分。

NEWになってすぐの頃にSSS+狙いで粘着していた運指を覚えていた。久しぶりにプレイしてみたところ、一発で何もかも上手くいった。かなり危ないところもあったなという感じなので、決め切れてよかった。今日は1-0や0-1を多く出していたし。しかし精度はあまりよくなかったと思っている。謎の赤が多かった印象。

たった4回で決めることができた。出したのはラスクレの2トラック目。これで出なかったら最後は別の曲をプレイして終わろうと思っていたので、ギリギリ。5鍵と高速4鍵は擦って、第二発狂(と呼ばれていたはず)はノーツを増やしてトリルと読み換える。ここまでは昔組んだ運指で、他の鍵盤は見たまま押すことができた。BPMが遅めなのでかなり余裕があるが、それにしても本当に上手かった。精度も良いと感じる。赤の数的には水晶世界と変わらないとはいえ、こちらはそもそもAJが出るだけで万々歳だからか。

立ち食いそばを食べて帰宅。疲れ果ててパソコンデスクにへばりつき、いくつか動画を視聴した。

www.youtube.com

先週視聴して日記にも書いた犬山たまきさんの3D LIVEのうち、恋愛裁判カバー部分だけを抜き出した動画。好みのシーンだったが1時間超の動画の一部なのでループ再生には向かないなと思っていたところだったので、大変助かる。ただのLIVE切り抜きではなく歌動画となるように編集されており、茶番シーンがばっさりカットされていた。それもまたいいよ。

www.youtube.com

15分11秒時点。この頃渋谷駅前のスクランブル交差点にデカデカと掲示されていた、花譜さんの武道館ライブの広告が映り込んでいる。思いがけず嬉しい気持ちになった。しかしこのような、明らかに動画の主題ではないことに反応するのはちょっと申し訳ない気持ちになるな。日記には好き放題書くがツイートするかどうかはしばらく悩んだ。

www.youtube.com

懲りずにまたにじさんじの公式番組で夜を明かした。その中から1本。剣持刀也さんがロリコンロリコン言われているのはしぐれういさんの切り抜きばかり見ていた頃から知っていたが、こうやって実際に幼いアバターVtuberに挟まれたときは普通の好青年になっていて、純粋にゲーム実況的な面白さがあった。この辺り弁えているからこその人気なんだろうなと感じた。ラストでスタッフを煙に巻くシーンがあって、急に入社日マウントを取り始めるのが本当に好き。話題とは一切関係ないことをすぐに持ち出せる発想力がすごい。22分27秒時点。

https://www.youtube.com/watch?v=KwxIJYdRl3s&t=1347s

昨日のCFのopen hacking phaseが終わっていた。全完6位のまま変わらないということで確定したので、アップした動画にサムネイルを入れた。

かなり眠い。日記は清書せず、今日やったことをサッとメモだけして午前5時半就寝。

06/09(木)

正午起床。昨日、にじさんじ運営会社のANYCOLORが上場したことを知った。さらなるご躍進を祈念している。

ANYCOLORが東証グロース上場、時価総額1652億円に。躍進続ける「にじさんじ」の魅力とは?【UPDATE】 | Business Insider Japan

準備して午後1時半に家を出る。まず学食で昼食。先週、納豆にはレジ1回につき1パックしか買えないという制限があることを知った。そこで今日は、最初に1パック買って席に置いた後、即座に戻ってもう1パック買った。納豆を見せると2回目かと確認されて、「2回目のレジだ」と答えたものの、プリペイドから引き落とされてしまった。これは納得いかないと「1回のレジで1パック」という制限であることを主張した結果、会計をやり直して、今度こそちゃんとミールカードで購入することができた。おそらく「1回のレジで1パック」という制限を「1食につき1パック」と勘違いされていたのだろう。

先週の一言カードには、日記に書いたような経緯と、納得いかないルールなのでなくしてほしいという要望を書いた。これに関する回答は次のようなものだった:「ミールカードのこのような制限は組合員の食生活を守るために設けている」「従業員間で再度ルールの確認を行う」。まず前者から、食生活を守るという目的なら何かを1食につき1個と制限するのはおかしな話ではない。しかし実際のルールの文言ではそのような制限のかけ方になっていないわけで、だのに存在しないルールを適用しようとされるのは後者ができていないことになる。1週間もあってルールの周知ができていないと見るか、まだ1週間しか経っていないと見るかは内情を知らないので何とも言えないが。

「食生活を守る」という目的を聞いて、「1回のレジ」を「1食」のことだと忖度することは可能だが、しかし僕がわざわざそのような解釈を行う必要はまったくない。もともと学食のレジ担当者はルールがガバガバなことが多く、それに甘えてきた経緯もあるので、正しくルールを適用されるなら諦めも付く。しかしより厳しいほうにルールを誤解されるのは我慢ならない。今日はそういう感じで一言カードにクレームを書いてきた。ちなみに、先ほど言っていたような忖度の話は敢えて触れていない。話が通じない人という空気を醸し出そうとしている。

一言カードを書いていたら遅くなった。午後3時開始のセミナーに少し遅れて到着。今日の前半はもう一人の発表で、教科書にあった天才的な構築について、全員で考えても結局よくわからないという結論になって終わった。もともと彼一人だけ発表する予定で、このままでは午後4時半と少し早い時間に終わりそうだったので、せっかくなら少し話したいと主張して僕も発表することに。意気揚々と黒板の前に立ったはいいが、1週間前に準備で読み返したきりの内容、しかも少し複雑な証明だったこともあり、再現するのに失敗して炎上。最終的に何とか補完できたものの、午後6時前までかかった。先週考えていたことは不正確で、十分に性質を拾い切れていなかったようだ。

午後6時に終了して帰宅。疲れ果ててなんと4時間以上YouTubeを見たりにじさんじ非公式wikiを読んだりしていた。

www.youtube.com

www.youtube.com

www.youtube.com

www.youtube.com

www.youtube.com

今日はぐんかんという、Vtuberテーマのネット小説で見たてぇてぇムーブを現実でやってしまっているにじさんじの男女コンビを発見して、一瞬で夢中になって脳を破壊されていた。実は僕「てぇてぇ」という言葉がまともな日本語と思えずあまり好きではなかったのだが、確かにこういうムーブを見せつけられると口角上がりまくってまともな語彙を失ってしまう。男女のライバーで身体的接触を行える、またそれを許容されるような関係性はさすがにフィクションにしか存在しないと思っていた。マジで最高すぎる。

セミナーの途中に先生にこういうものを作れないかと言われていたプログラムを書いてメールで送信した。行列計算や統計処理が含まれるもの。R言語で実装できないか聞かれたが、自分はそれを使えないのでOctaveで書いた。

またYouTubeに戻る。それと並行して、おすすめのなろうまとめの編集を再開した。しかしついうっかりなろうの読み返しを始めてしまい、そのまま朝まで戻ってこれなかった。馬鹿野郎。「最強魔法師の隠遁計画」は読んだのが高校生の頃で今の好みから外れたかと思っていたら全然そんなことはなく、昔好きだったシーンが今も好きであるということをずっと再確認していた。

https://ncode.syosetu.com/n5606cq/

これはまずいと一旦日記を書き始めた。日記を書きつつまたYouTubeを見てしまう。

以下の動画の51分57秒からは森中花咲さんと剣持刀也さんのデュエットでトンデモワンダーズを歌っている。これが抜群に良かった。特に剣持刀也さんの歌が上手すぎて初めて聞いたときマジでひっくり返るかと思った。配信のメインじゃないけど日記だから彼だけに言及しちゃうぞ。まず冒頭ですぐプロセカバージョンのMVと似た声をしているなと感じた。それなりに高めの声でクールに歌っているのが良い。早口の歌詞にも関わらず一音一音はっきり発音されていることからも原曲のボカロっぽさを感じられてどんどん好きになっていった。

www.youtube.com

午前11時就寝。

06/10(金)

午後10時起床。たくさん眠れて偉い。しばらくYouTubeを見てから起き上がった。

昨日先生に送信したOctaveコードについて、R言語に書き直したものが研究室の先輩から送られてきていた。読んでコメントをくれとのことだったので、一念発起しR言語の環境を整えることにした。といってもUbuntuだとapt-get install r-baseするだけだったので非常に簡単。それで実行して、確かに正しく動いているのを確認。一応一か所パフォーマンス的に嬉しくなさそうなところを指摘したものの、本質的ではないなあと自分でも思う。

午後1時半からCF #798 div.2。火曜日は失敗したURL貼り付け時のタイトル表示だが、この記事を書いているときはうまくいった。一度表示できてしまえばこちらのもの。当然火曜日の分も貼り付けなおせば表示されるが、いちいちそういう対応をするのは面倒なので、これからはその時々で貼り付けた状態をそのまま放置することにした。

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

Aから微妙に難しい気がする。abで文字が共通しないので、貪欲に取るのが良い。Bは先頭から貪欲に埋めても最後の2つを入れ替えたりすればちゃんと条件を満たせる。Cは単純な木dp。Dは45度回転して各軸における座標の最大・最小を求め、その中央の近くを試せば十分。45度回転を戻したときにちゃんと範囲内になることは要チェックか。ちょっと怖いので各座標で試す範囲を\pm 5とした。実はそもそもn\times mマス全部試すのが想定解だったらしい。

Eは難しい。デクリメントがあることを完全に忘却して、まず最初の状態で連結成分を求めて、偶数をいくつか奇数にすれば全部繋げられるなと考えていた。これで1WA。デクリメントの存在を再発見し、思ったより難しいことに気づく。しばらく考えて、LSBで分類すると高々2手(ただし0\rightarrow 1を除く)でよいことが分かった。LSB最大のものをデクリメントすることで、それ未満のLSBを持つ要素全部と連結にできて、残りLSBが同じものについては一つ選んでインクリメントすれば十分。よって0手か1手で達成できるか確認するという問題になって、0手は愚直に、1手はすべての\pm 1を全探索して、連結性をO((\log\max a)^2)で判定して解いた。判定は各bitを頂点とし、要素ごとに立っているbitたちを結ぶ辺があると見たときの連結性に言い換えられ、各bitのペアについてそれを両方含むような要素が何個存在するかカウントしておくと差分更新できる。

システスも全部通って15位。

午前3時から日記を書き始めた。昨日から日記を書いている間YouTubeでNJU歌謡祭2021をずっと流していたのだが、朝方ついに完走した。後半にあるニホンノミカタはインタビューまで含めて一つの流れだったらしく、元ネタを調べて完成度の高さに笑っていた。最初にこのアーカイブを再生した時は、知っているVtuberが歌っている部分だけ飛ばし飛ばし見ていたので、こうやって全編通して見る機会を作れたのは良かったなと思った。

www.youtube.com

www.youtube.com

後半の2時間24分19秒時点、インタビューでリゼ・ヘルエスタさんとアンジュ・カトリーナさんが決めポーズについて話している部分。この後のどこかでチャリで来たポーズを決めたいねと言っていて、もしやと思って最後のVirtual to LIVEをじっくり見てみたら見事に成功させていた。3時間14分29秒時点。これだけで目を灼かれるくらい良いな。

https://www.youtube.com/watch?v=zoynMroawZw&t=8659s

https://www.youtube.com/watch?v=zoynMroawZw&t=11669s

ハーメルンを1作読み始め、そのまま最新話までたどり着いてしまった。日記を書いていたんじゃないんですか?「幼馴染がVTuber始めたら友人Aちゃんと呼ばれるようになった件」。幼馴染がVtuberを始めて、配信で話題に挙げられるためファンに認知されてしまったという設定は似たものをカクヨムでも読んだ記憶がある。僕はそういう設定が好みなのだが、これは結構一般的な感覚なのだろう。この作品もかなり好みでエタっているのが残念。

syosetu.org

しかし結局こういう設定は「人気者と特別仲が良い自分」に対する優越感が根底にありそう。その人気者の位置に今ドキ風にVtuberをメインに据えるのも、ラノベでよく見るようにアイドルをメインに据えるのも本質的には変わりないなと考えてしまった。Vtuberとアイドルの違いは自分でもできそうと思えるかどうかだと思っていて、それを押し出した作品がより良いのか。しかし演者をメインに描こうとするとすぐ炎上だったり人間関係だったりドロドロした話になってしまいがちなので、考え物。

結局そのあとも別のハーメルンを読み始めたりしてほとんど書き進められなかった。午後0時半就寝。

06/11(土)

午後4時前に冷凍弁当を受け取った。またすぐ寝て、午後8時起床。食事してYouTubeを見て、午後9時からABC255に出た。

Aising Programming Contest 2022(AtCoder Beginner Contest 255) - AtCoder

今日はA問題の問題ページを事前に開いておいたが、すぐ短くなりそうな見た目ではなかった。以降Ex問題まで全部C++で実装。Aはよい。Bはちょっと題意を把握するのに手間取った。Cはかなり難しめ。まずD=0のケースを処理し、D\lt 0D\gt 0に帰着しておく。あとはA+Di\le X\lt A+D(i+1)のような不等式を解いて高々2か所チェックする。Dは自明。

Eはそれなりに難しいものの考察がスムーズに進んでかなり素早く解けた。とりあえずA_1を固定して一つ良い数列を作っておけば、適当にずらすことですべての良い数列を考えたことになる。ずらすとA_1\leftarrow A_1+xならA_2\leftarrow A_2-xのように交互に増減することを踏まえ、各位置についてラッキーナンバーにするときに欲しいxを求めて、最も重複するものの個数を出力する。FはP_1が木の根になっていて、それのIにおける出現位置の左右で列を分割すると左右の子の部分木に関するIが得られる。このIに含まれる要素はPにおいてもまとまって出現している必要があり、その部分がIに対応するPになっているので、再帰的に解く。

Gは実装がつらい。考察を進めると、Grundy数は大体連番になっていて、石の数がどれかのXに一致するところだけたまに変な値が出現して全体が後ろにずれるとわかる。よって全体のGrundy数は連番となっている区間に分割することでO(M)個の情報で保持できる。Grundy数のカウントを連番と変な値に分け、連番の分仮想的にカウントが+1されていると見なせば、実際にXに対応するGrundy数を求めるのはmapで行える。Exは座圧して区間ごとに含まれるインデックスの和を持っておくことで遅延セグ木に乗る。実が増えるのはインデックスの和の係数に対する区間加算になって、収穫は値のセット。Nの制約が大きいことに気づかず、最初長さNの遅延セグ木を作ろうとしていた。

全完。Gのしょうもないミスで1WAし、順位は6位になった。

コードゴルフ。Aは冷静になるとdcで素直に書ける。コンテスト開始から1時間以上経ってようやく気付いたものの、ちゃんと開始すぐに同じコードを書かれた方がいて負け。BはRubyで、複素数abs。Cは謎。とりあえず自分の解法をRakuで実装しておいた。Dみたいな大量に二分探索を行う問題はOctavelookupが強い。最近活躍する機会があまりなかったので、久しぶりに使えて気持ちいい。EはPerl。インデックスの偶奇を得るため特殊変数$|を用いているが、ゼロクリアしていないのでNが奇数のとき正しくない挙動をするはず。なのに通った。よくわからない。以降は手付かず。

今日のABC255もリアルタイムで実況しつつ参加していた。この録画の編集を日付が変わったあたりから始めた。発言がない部分を切り詰めるという編集スタイルを知ったので、今回はそれを試してみたい。

AviUtlに動画を読み込み少しカットしたところ、音ズレが発生してしまった。調べるとフレームレートが固定か可変かの違いによるものらしい。僕が使っているキャプチャソフトShadowPlayは可変フレームレートでしか録画できず、一方AviUtlは固定フレームレートにしか対応していないようだ。AviUtlの入力プラグインの設定を弄って再度読み込んでも変わらなかったので、動画自体を固定フレームレートにエンコードしなおすことにした。

HandBrakeというソフトをインストールして、実行。これにもしばらく時間がかかった。しかも出来上がったファイルをAviUtlに読み込ませると例外が発生してしまう。入力プラグインL-SMASH Worksを優先的に使うようにして何とか解決。しかし今度は一部の操作が異常に重くなった。先ほどのエンコードでは元のファイル2.2GBから出来上がったファイルが600MBほどで、つまり圧縮されてしまったのが問題らしい。調べると無圧縮に変換するとよいと書いてあったものの、やり方がよくわからなかったので、操作の重さに耐えつつ編集を進めることにした。

幸い動画の一部を削除するのが激重なだけで、動画の一部を別のところに移動させるのは大丈夫だったので、それを多用し削除を保留するような形で編集を進めた。先ほど述べたような編集スタイルでは大量のカットが発生するので、このことに気づかなければ待ち時間が長すぎて途中で心が折れていただろう。無言かつ画面に動きがない部分をチマチマカットし続けて何とか最後までたどり着いた。この時午前7時。本当は重要でないシーンもばっさりカットするべきだったのだろうけど、考察シーンもコーディングシーンも全部動画に残したかったので、元70分弱だった動画は結局50分強になった。このあたりゆっくり実況なら倍速をかけていたのだろうが、一応喋りながらコーディングしていたし……。

適当にBGMを設定して完成。この状態でチェックする気力がないのでとりあえず出力する。カットした部分の処理に時間がかかるようで、これには80分ほどかかった。その間はまたYouTubeを見ていた。途中でBGMをフェードアウトさせる設定を忘れたことに気づいて絶望。もう何もかも面倒になって修正しないことを決定。次に、出力された動画を再生しておかしなところがないかチェック。これは主に音だけ聞きたかったので、日記を書きながら流しておいた。

全部完了して午前10時に投稿。序盤のサクサク解いている部分だけなら結構見てもらえるのではないかと思う。全部通して見る物好きがいるかというと……毎週2万文字くらい投稿される週記を読んでくれている人がいるように、50分僕がボソボソ喋っている動画を見てくれる人も誰かいるだろう。そう、ちゃんとマイクに向かって発言することを意識しないとすぐボソボソ不明瞭な話し方になるのは改善すべきところだった。しかしそもそも生声実況の編集は音ズレなどの問題でかなり面倒であることに気づいてしまったので、今度動画を作るときはまたゆっくり実況に戻るかもしれない。

www.youtube.com

合間に昨日から読んでいたハーメルンを1作読了。「24歳、男性。Vtuberを始めるも、女性ファンより男性ファンが多い件について。」。あまり設定が好きではないのにVtuberモノだからと何となく読み始めたら思ったより重い話が多くて、全体的に辛かった。

syosetu.org

さらにいくらか日記を書いて、午前11時半就寝。

06/12(日)

午後4時半起床。午後5時からOpenCupの代理コンテストがあるので、それまでに食事をしたい。冷凍弁当をレンチンしつつ合間の時間で機械学習のコードを書き換え実行しようしたら、案外時間がかかって弁当を食べる前にコンテストの開始時刻になってしまった。結局コンテスト中に食べた。

今日のコンテストタイトルはPKU Contest 2, PTZ Summer 2021 Day 5。今日はチームメイト一人が参加できないらしく、二人だった。思い返せばこれまで一年近く、みんな毎週参加していたのが偉すぎる気もする。結果はAEGCDの5完だった。コンテストリンクを貼っておいて、問題に対する言及は解法だけにしておこう。どういう問題だったかは以下のリンク先を参照してほしい。

https://www.acmicpc.net/category/detail/2800

Aはどんな操作でもコストが一意。Eは部分長方形の行を決め打ち、数列に関する問題に帰着する。そうすると最大値を削除して区間をマージするのを繰り返すことでソートを除き線形で解けるため、全体でO(n^2m\log m)になる。うっかり数列に帰着する部分でO(nm)かけてしまい1ペナ。さすがに頭が回ってなさすぎる。次にチームメイトによってGが通された。

Cはn=1の場合を除いておけば、(円状に並べて)隣接する値が一致する確率を独立に求めて足し合わせることで答えになる。ここで、sの長さaについて、f(s)=1\dots aのそれぞれの値を取る確率を考える。sの周期が重要になって、aの約数を昇順にd_1,\dots,d_kとおくと、f(s)=1\dots d_1の確率はそれぞれ同じ、f(s)=d_1+1\dots d_2の確率はそれぞれ同じ、……となるようだ。よって、隣接するa_ia_{i+1}の約数を列挙しマージすることで、各値を取る確率が同じになる区間に分けて計算すればよい。この制約のもとk\le 128なので間に合う。

DのLを固定する方針だけ立てて、考察の後半と実装はチームメイトにやってもらった。定数倍に大変苦しまれている間BとFを考えて、どちらもそれっぽい解法を考えたものの正当性がわからない。残り30分でDが通ったのでBに特攻し、3ペナほど吐いて終了した。

コンテスト後にFを実装したら20分で書いたコードが一発で通った。こちらに進んでいれば完数を増やせていたらしい。aが零行列になるまで、一番上の非ゼロの行を消し、残っている中で一番左の非ゼロの列も消す。これで一つ\vec b\vec cのペアが決定する。この操作を繰り返して、aが零行列になる前にKが足りなくなったらダメ。逆に余った場合、二個ずつ組にしてb_1=1c_1=\pm 1を入れる。一つ残った場合は直前の組を少しずらして、それを打ち消すようなものを入れるのが良い。基本的にどの要素も\pm 1のどちらかを選べばまた非ゼロ要素にできるので可能。基本的にと言ったので、そうでない場合をいくつか場合分けする。

まず、簡単なものとして「直前」がない場合、つまりK=1かつaが最初から零行列だった場合。これは当然不可能。次に、p=2の場合はずらすと\vec 0になる可能性がある。具体的には、\vec bまたは\vec cのどの要素を選んで\pm 1しても操作後に\vec 0になってしまう場合。0\rightarrow 1ができることに注意すれば、このようなケースはp=2に加えn=m=1を満たすとわかる。この場合は最初にa_{1,1}パリティKパリティを比較して処理しておくのが良い。

解説をいくつか読んだ。Bの\bmod{p+q}で考えるという考察は見覚えがある。見るたびあまりの天才性にひっくり返っている。これこのコンテストで5番目に解かれている問題ってどういうことなんだ。IのN=6のケースはヒューリスティックに求めよと書いてあってげんなり。大きなケースのヒントではなかったらしい。そういう優しさのあるコンテストではなかったか。一方N=20のケースの構築方法はこれまた天才的だった。そもそもオートマトンである文字列が受理されないとは、遷移後に終了状態にないということであって、決して途中で遷移先がなくなったということではない。このことを勘違いしていた。

少しYouTubeを見た。実はカバンチェックがあるというのは事前に言われていたらしい。そういう企画はオモコロで見覚えがあるし、最後に謎の格言を大声で喋っているのもオモコロっぽい。面白いのでOK。確かにVtuberの演者のリアルに繋がることは徹底的に排除されるべきだから、予告なしのカバンチェックなどタブー中のタブー。

www.youtube.com

午後11時半からECR130。

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

Aはやるだけ。Bは大きいほうからx-y+1\dots x番目の和なので、ソートして累積和。Cは'a''c'の相対的な順序が固定されていて、間を'b'が動くと見なせる。しかし'b'だけ抜き出したりするような実装が面倒だったので、普通に先頭から合わせていった。まだ使っていない最も前にある文字を正しい位置に持ってこれるかチェックする。操作の順序は答えには影響しないはず。

Dは先頭から見て、まずその位置の文字がこれまでに出現したか判定する。出現していない場合はクエリ1で特定。出現している場合は、どの位置まで区間を広げれば今見ている位置の文字が出現するか二分探索する。普通にやると\lceil\log_2 n\rceil回かかるが、これまで出現した各文字の最も右に位置するインデックスを集めてソートしそれだけ見ることで\lceil\log_2 26\rceil=5回になる。最初の判定と合わせてクエリ2は高々6n回で、ギリギリ制限を満たす。二分探索の条件で頭を壊してしまい1WA。

Eはかなり迷走した。同じ色で塗れる点の集合、特にサイズが2以上のものを考える。まず、同じ集合に属する点は互いに最も近い距離にある必要がある。さらに、逆に各点について最も近い距離にある点が全部その集合に入っていなければならない。以上のことから、それらの集合を全通り集めてきたとき、どの二つも共通部分を持たない。それぞれの集合について全部同じ色にするか全部バラバラの色にするかの二択になり、これを遷移として使った色数を持つdpが書ける。どの色とも同じ色で塗れない点は先に処理しておく。最後に、色数に応じてどの色を使うかの場合の数を掛けて答えになる。

Fは解けず、23位。open hacking phaseが終わっていないので暫定的な結果。Dの最初の判定も二分探索に含めることで、クエリ2を高々\lceil\log_2 27\rceil n=5n回におさえられそう。Eのdpは謎の次元を増やしてしまい計算量が悪い。これはn\le 100という制約に助けられた。さらにtypoでうまく\bmodを取れていないが、こちらはギリギリ大丈夫そう。Fは2-SATらしい。

ネット小説の更新を漁っていたら午前4時になってしまった。溜めていた日記を書き始める。相変わらずYouTubeに気を取られつつ午前10時までかかってこの位置まで書き進めた。

Vtuberにハマってから明らかにPC作業の集中力が落ちている。もともと昔から作業用BGMのため常にバックグラウンドでYouTubeを開いていて、一年ほど前にモニターが5枚に増えてからは一画面をYouTubeに使うようになって常に動画が見える状態だった。これまでは曲のPVや一枚絵が表示されているだけだったそこに、今はVtuberが四六時中映っている。やるべきことに手を付けられないことを除けば、今の環境はまあ、幸せである。

一瞬外出。生協でパンやお菓子と注文していたラノベを購入して帰宅。

書いた日記を推敲していたが、問題の解法を説明する文章がどうにもうまく書けず苦しんだ。特に自然な言い方にはなっていないし、かといって曖昧さを排除できているわけでもない、中途半端な形である。ほどほどに諦めをつけ、正午を過ぎてようやく完成。

週記(2022/05/30-2022/06/05)

05/30(月)

日曜日は週記を投稿してからすぐ布団に入り、少しYouTubeを見て午前9時前に寝た。

いい感じの時間に起きて少し進捗を生んでからインターン先定例会に出席しようと思って、午後2時から30分おきに目覚ましをかけていた。一応意識は取り戻すものの布団から身を起こすことができずまたすぐ寝入ってしまい、気づいた時には午後4時半になっていた。飛び起きてオンライン会議に接続。ギリギリセーフだった。

先週の進捗は、ない。集中講義だったということで許してもらえないだろうか。そもそも自分で自分を許すべきではない気もする。これまで書いたコードが今、デプロイされたことによって自分の手を離れたところで動いているはずだが、それに関するフィードバックも一切ないため本当に報告できる進捗がない。先週水曜日の日記に書いたようにキャッシュの問題でうまく使えないということもあり得るようなので、そもそも動いているのか心配である。これに関してはまたメッセージで確認の催促をしておく。

勉強会まで終えてからは、ずっと講義の課題に取り組んでいた。先週と同様に今日締め切りの課題が2つ、明日締め切りの課題が1つあって、気合を入れて全部終わらせてしまった。ゲーム理論離散数学については特に感想もない。

ハードウエア基礎は面白かった。MOSトランジスタを用いていくつかの論理回路を作るという話で、まずNOT回路がトランジスタ2個で実現される。そして、次に作るのがNANDとNORだった。それぞれ並列・直列つなぎを用いるという自然な発想からトランジスタ4個ずつで実現されていたが、そのように素直に構成したものがANDやORではなくその反転であるという事実に衝撃を受けた。NANDのみですべての論理回路を構成できることは事実として知ってはいても、パズルの一種以上の意味はないと思っていた。案外そうでもないらしい。

さらに集中講義の課題に取り組みつつ、午後11時から1時間ほどしぐれういさんの配信を視聴していた。いわゆる赤スパが結構乱れ飛ぶ配信であったが、特に5万円のスパチャが流れたときにコメント欄が大盛り上がりだったのが印象的。1万2万出すのと5万出すのは結構違う受け取られ方をするようだ。額面が大きすぎて、自分では差に想像がついていない。

www.youtube.com

平面グラフの頂点数と辺数について、V\ge 3のときE\le 3V-6という関係が成り立つ。これを用いて、整数nであって「任意のn頂点グラフについて自身と補グラフのどちらかは非平面的」を満たすようなnの最小値を評価せよという問題があった。結論から言えばn\ge 11が出る。ではn=10では自身も補グラフも平面的な例があるのかと思って、しばらく適当なグラフを作っていたのだが、すぐK_{3,3}をマイナーに持ってしまう。結局構成できずTwitterに質問を投げた。

リプライで、n\ge 9ならどちらも非平面的になることが示されていると教えてもらった。「EVERY PLANAR GRAPH WITH NINE POINTS HAS A NONPLANAR COMPLEMENT」というタイトルの論文。読むと、次数列でいろいろ場合分けして各個で示しているようだった。そちらに深入りはしないものの、n=8で両方平面的になるようなグラフがあるのならそれは構成しておきたい。適当に頂点を繋いでみると一発で見つかった。

辺がぐにゃぐにゃしていて大変複雑なグラフに見えるが、並び替えてみると見事に綺麗な平面への埋め込みが得られた。ほかにも補グラフが孤立点を持つような構成があったりと、n=8なら適当にやってもすぐ見つかるらしい。それがn=9になった瞬間全部ダメになるというのだから、驚きの事実である。

午前3時くらいから集中が切れてハーメルンを読み返していた。「輝きたくて」。何度も読み返している作品だが、最近Vtuberを見るようになってまた新たな発見があった。というか、元ネタとなったVtuberをいくらか判別できるようになっていた。しかしこれ、何回読んでも面白いな……。

syosetu.org

そんなことをしていてはいけないぞということで気合を入れてページを閉じ、日記を書いてゴミを出して布団に入った。明日もミーティングがある……と思いながら少しなろうを読んで、午前8時半就寝。

05/31(火)

午後3時前に起床。準備して1時間ちょっとのミーティングへ。

ちょっと新しいことを始めることになりそう。今そちらは手が足りていないらしい。こちらとしてもデプロイを終え一段落ついた感じがするし、進捗をほぼ産めない状態が続いているから、この辺りで一つ誰かと連携して作業することでちゃんと毎週稼働するペースを作っていきたい。というか、僕自身の稼働より会社から貸与されたPCの稼働が問題で、せっかくごっついGPUを備えた物を送ってもらったのに、いつの間にか機械学習を使わないコードばかり書いてしまっていたのが気になっていた。

終えてからもちょっと考え込んでいたら、購買が閉まるギリギリの時間になっていた。原付を飛ばして駆け込み、カロリーメイトを買ってミールカードの残高を調整。そのまま夜の部が開店した学食で食事して帰宅した。購買の閉店時刻と学食夜の部の開店時刻が一致しているのは辛い。

かなり眠気があって布団に倒れこんだ。しかし眠らず、しばらくにじさんじ非公式wikiを眺めていた。今、現実のVtuber(?)を少し見るようになって、現在どのように活動しているかは何となく感じ取れる。しかし人に歴史ありということで、現在に至るまでの数年間の活動から生まれた膨大なエピソードに圧倒されていた。リンクされていた動画に飛ぶと非公開になっていたりするのも、Vtuberという存在が誕生してから経過した時間の長さを感じる要素。

人が泣いているのに弱いので、こういうシーンを説明されるとすぐ自分も涙ぐんでしまう。

youtu.be

午後9時前に起きあがって、昨日の続きで集中講義の課題に取り組み始めた。途中でICPCの参加登録が始まったので、とりあえず個人アカウントの設定を確認して、学士から修士に変更したりしておいた。

午後11時半からCF #795 div.2。

Dashboard - CodeCraft-22 and Codeforces Round #795 (Div. 2) - Codeforces

Aはよく見ると偶数か奇数のみの列になる。Bは靴のサイズの小さいほうから誰のところに行けるか考えると、サイズが同じ人たちで交換し合うしかないことがわかる。よって各サイズに2人以上いる必要があって、いる場合は適当にrotateしておけば十分。Cは各桁に対するf(s)への寄与を考えると、末尾が1、先頭が10、残りは全部11であるとわかる。従って、できれば末尾に'1'を持ってきておきたい。最初にそれを試して、次に先頭に'1'を持ってこれるか試すことになる。'1'が一つしかない場合に注意。

Dは\maxを決め打つと使える区間がわかるので、区間aの和を最大化する。累積和を取っておけば、右からその最大値を取って左から最小値を取ると言い換えられるので、適当にデータ構造を使えば解ける。区間のマージと読み替えると線形でも解けそう。Eは区間の端点でイベントソート。区間が消えるタイミングでもっと右にある別の区間と「直接」繋がっていなければカウント、という大嘘をついて1WA。間接的につながっている場合もある。結局UFの辺を頑張って省略するのが間違いがない。ちょっと考えると、例えば赤の区間が消えるタイミングで青の区間に辺を張るとき、その時点で保持している青の区間すべてに対して辺を張っておけば、以降青の区間は最も遠くまでカバーするものだけ残しておけば十分とわかる。これで辺を張る回数が線形になって、通った。

Fはいかにも全方位木dpのような装いをしている。まず木dpを考えてみると、各頂点に対してSLCAが自分になる場合の数を求める方針が立つ。uの部分木の頂点数をc_uとすると、とりあえず\binom{c_u}{K}通りあって、ここからもっと下の頂点がLCAになる場合を引く。一段下の子を考えた瞬間に完全に独立した事象となるので包除原理は必要なく、uの子vに対して\binom{c_v}{K}を引くだけで求まる。こうして求めた場合の数にc_uを掛けて答えに加えることになる。そして、このように一段階下の子しか見ないなら容易に(別に容易ではない)全方位木dpに書き換えられる。uからvに移動するときはuvの持つ値のみを注意深く修正すればよい。今いる頂点を根としたときの値を持ち続けることを意識するのがコツか。

システスは全部通って6位。Eで迷走したのが痛い。Fの全方位木dp部分はなんだかんだ更新12行・巻き戻し12行とすごい実装になってしまったが、一発で合ってくれて助かった。しかしtouristはCFのルールでtourist出しして1位を取っており、圧巻。

ハーメルンを1作読了。「ありきたりな正義」。集中を切らしすぎて課題レポートを書きながらチラチラ読み進めていた。設定は好みで、展開は今のところそこまででもない。原作前スタートだが大胆に時間を飛ばしてくれているのですぐ1巻時点まで辿り着きそう。

syosetu.org

午前9時頃までかかって、ひとまず課題となっていた設問にはすべて回答を作成できた。あとは講義の感想が求められている。先週の週記で毎日面白かったところをまとめていたので、それを引き写してくればよさそう。追加で昨日見つけた、頂点数8で自身も補グラフも平面的なものを載せておけば十分だろう。これでついに課題レポートが完成。ページ番号を振ってみたところ、実に19ページあった。スキャンの手間も無視できないサイズ。06/05期限だからと言ってギリギまで溜めていたら大変なことになっていただろう。

レポートを提出してしばらく日記を書いた後、生協に向かった。食事して、予約していたラノベを受け取り、床屋で散髪。今日は眠すぎて髪の毛に鋏を入れられている時ですら容赦なく首をグラグラさせてしまった。また、ついに200円ほど値上げしたようで、世知辛い。

帰宅して5月分の読書記録をツイートした。今月は何に時間を吸い取られていたのかわからない。なんだかラノベをうまく読み進められない時期があった気がする。文章をじっくり読んでしまってページが進まない、という感じ。適当に読むという能力も必要らしい。

午後2時前にこれまでの日記が書きあがり、すぐ寝た。

06/01(水)

消えた。

06/02(木)

午前0時半起床。

DDCC2022の予選申し込みが始まっていたので、登録しておいた。今年は新卒枠に入れるので予選通過しやすそう。いや、去年も新卒枠だった気がしてきた。理系大学生は二度卒業するということで。

YouTubeを見ながら午後からのセミナーの準備を始めた。結構前に作ったカンペがあり、そこにメモしていない行間を再現して記憶を掘り返す、必要ならばメモを書き足す、という作業になる。それが最初に準備したときを含めてこれで3回目。さすがにここまで発表の機会が遠のくとは思っていなかった。ちゃんとメモをするべきだとわかってはいるが、しかしちょっと考えればわかると判断したからカンペに書かなかったのであって、直前に急いで準備している状態だとそんなのに紙幅を割くのは面倒だなあと考えてしまう。余裕を持って準備する必要がある。

以下、セミナー準備について話すことはないので、見ていた動画についていくつか書いておく。

www.youtube.com

昨夜、犬山たまきさんの3D LIVEが行われていたらしい。ゲストもかなり豪華。やはり動画になると、生配信より情報の密度が高くなってより面白く感じられる気がする。まあ用意するのは大変そう。いくつか特に好きなシーンがあるので、以下に列挙する。

38分26秒。「判決は……」のセリフとともにしぐれういさんの眉がキリッとするのが良すぎた。細かく表情が変わるのすごいなあ。どういうトラッキングを行っているんだろうか、あるいは手で表情を付けているのか。

https://youtu.be/Rzxdn5YT_BM?t=2306

40分50秒。「うい先生盆踊りしてる?」というコメントがあって、探して見つけた。このシーン、後ろで踊っているしぐれういさんの振り付けが確かに盆踊りのように見える。可愛すぎ。

https://youtu.be/Rzxdn5YT_BM?t=2450

またその少し後から舞元啓介さんが歌い始めるのも非常に良かった。それまでもしぐれういさんの切り抜き経由で何度も目にしていたが、火曜日に氏の非公式wikiを読んでからより直接的に興味が湧いている。

ただ↑の動画はループ再生には向かない。今日の作業用BGMはこれ↓。これまた火曜日にNJU歌謡祭2021のアーカイブをところどころ見ていて、特に気に入ったシーンのうえ探すとそこだけ切り抜いた動画が公式で上がっていたので採用。一番気に入ったのはラストのVirtual to LIVEだが、これはさすがに動画にはなっていなかった。ライブで歌っているということで、歌動画として考えれば完成度は高くはないのだろう。しかしなぜかループして聞いても全く飽きない。

www.youtube.com

朝になったので切り上げて布団に入った。午前9時就寝。

午後0時半、外から大きな音が鳴って起床。雷らしい。その後すぐ強く雨が降る音が聞こえてきて、セミナーのため山に登るのが億劫になった。午後1時半ごろに布団から出て、外を見ると案外晴れている。天気予報を確認すると、夜までは何とか天気が持ちそうな感じだったので、カッパだけ持って原付で山に登ることにした。

学食で食事。いつものように納豆を2パック購入したら、片方をプリペイドで会計された。どうやら1回のレジにつきミールカードで納豆は1パックしか買えないという制限があるらしい。確かにそういう制限の一覧を学部1年生のころに見た記憶はあるものの、それ以来4年以上通って、特に引っかかった記憶がない。こうやってルールに厳しい人と厳しくない人がいると計算が狂うので困る。しかもなぜか、ミールカードによる会計とプリペイドによる会計が分けて行われていた。それはもうレジに2回通したのと何も変わらないだろう(屁理屈も理屈である)。納得いかなかったので一言カードにクレームを書いてきた。もしこれによってルールが厳格化されるなら、ちょっと余計なことしたなという気持ちになるが、今日みたいに急にプリペイドから引き落とされるよりはマシだと僕自身は感じる。

山に登って午後3時からセミナー。今週ももう一人の人は集中講義に出席するそうなので、今日は僕と指導教員の一対一になった。用語や記号の定義はだいたいすっ飛ばしての発表にできるから、もしかしたら用意していた分で足りないかもな~と思っていたら、2時間半ほどでA4用紙に6ページ分書いたメモの1.5ページ分しか終わらなかった。これだけ進みが遅かったのは脇道に逸れまくっていたから。急に競プロの過去問の話を始めてみたり、先生に定理や証明を深堀りされたりした。僕がふ~んとしか思わなかった不等式評価のタイトさについて例を挙げて確認してみたり、やはり着眼点が違うと感じる。

川内の学食で食事し、午後6時半帰宅。50分もある↓の動画を最初から最後までしっかり見てしまった。信じられないくらい面白かった。この回のゲストは、これまでずっとナレーションを担当されていた方らしく、最終回にしてついにゲストになったようだ。そういう展開からしか摂れない栄養素は確実にあるだろう。最終回だけ見てる奴が何言ってるんだという感じだが。

www.youtube.com

49分55秒。手の形を見るに花束を持っているようだ。こういうところまで見て取れるトラッキング技術はやはり凄い。体の比率と3Dモデルの比率が微妙に合っていないのかモノを食べるときに手が口元からずれてしまっているが、それ以外は特に違和感なく体が動いている。各人が何をしているのか細かくわかるのも、ついつい動画に引き込まれてしまう理由の一つだと感じた。

https://youtu.be/CGksvc8lwm8?t=2995

午後8時半からインターン関連のコーディングを開始。明日何やらペアプログラミングをするようなので、それまでにひとまずのコードを書いて、機械学習の実験を回しておきたい。半年以上前に書いていたコードを見て記憶を蘇らせるのとググってサンプルコードを拾ってくるのを繰り返し、何とか動くコードが書けた。

適当に学習を回し始めた後、勢いづいたままこれまで書いていたコードの修正と追加実装を行った。ある2つの列を順序バラバラで最もらしくマッチングさせる必要がある。つまりは最大重み二部マッチングで、フローなら多項式時間で解けるのだが、さすがに実装が面倒だったのでとりあえずbitDPを書いておいた。列が長すぎる場合は即座に異常な値を返すようにしてあるので、とりあえず落ちることはない。実際にそのようなケースが発生してから書き直すことにしたい。結局自分の作った機能のテストなので、変な挙動をしても今のところ自分にしか影響がない。

午前4時までコーディングしていた。Excelの謎の挙動に悩まされて大変苦しかった。このように自分がただただ苦しんでいる時間も業務上必要だったと思っているので、作業の記録に含め、時給を発生させた。進捗ではなく自分の支払った労力をカウントしている。

またしばらくYouTube。レバガチャダイパンが面白かったので、アーカイブから少し見ていた。FFの友人が結構前から戌亥とこさんにハマっていたこともあり、↓の回を選択。これまで歌動画しか見たことがなくて、かっこいい声をしている方という認識だったが、普段の声の落ち着きと可愛らしさが同居している感じがかなり好みだと分かった。しぐれういさんの声はひたすらに可愛らしく、星街すいせいさんの声はハリのある強さを感じて、それぞれ普通ではない点で良さがあると思っているところ、戌亥とこさんの声はその普通さが良いとも言える。

www.youtube.com

午前7時から午前8時半まで日記を書いていた。布団に入って動画を見たりカクヨムを読んだりし、午前9時半就寝。

06/03(金)

今日のペアプログラミングは夕方からということしか決まっていなかったので、午後3時から1時間ごとに目覚ましをかけていた。すると、午後6時ちょっと過ぎの連絡に午後7時になってようやく気付くという事態に。申し訳なくなりながら起床し、食事して午後7時半から開始。

昨日回してから寝た機械学習の実験が終わっていたので、結果を報告。その後しばらく話していて、自分がoptimizerとschedulerを混同しており、片方しか設定しなかったせいでLearning Rateを一切変えないままずっと学習してしまったことに気づいた。一瞬で過学習したのも当たり前だったか。それの修正と今後の実験の方向性を確認しつつ、ライブラリの実装を読んだりしていた。通話は2時間ほどで終え、その後午後10時までコーディングを続けていた。学習を回し始めて完了。久しぶりにバリバリインターンの進捗を出せている感じがして気が軽い。

YouTubeの動画をいろいろ漁って時間を過ごし、午後11時半からCF #796 div.1に出た。

https://codeforces.com/contest/1687

Aから難しかった。最初、始点を自由に決められないと勘違いしていて、最初に右に行くか左に行くかなど考えていた。その後始点が自由であることに気づいてからも思考が固定されて、どこからどこまで往復するか全探索する方針の正当性を示そうとしていた。問題文に書いてあることをそのまま実装するとどうにも場合分けなど大変そうだったので、何か簡単な方法がないか考え、ようやく各座標を最後に通った位置だけが問題になると気づいた。直ちに\min(n,k)個の座標を一直線に移動する場合だけ考えればよいことがわかり、実装してAC。

Bは冷静になると簡単。まずm回のクエリで各辺の重みを求める。次に辺を重みでソートして、順に最小全域森に使うかどうか決める。それまでの最小全域森が分かっていれば、そこに辺を追加してみて、重みの増分が追加した辺の重みと一緒である場合だけ使用するという方法で次の最小全域森が求まる。「最大」の全域「森」というほとんど見ない概念に惑わされ、辺を並べ替えることをなかなか思いつけなかったのが反省。実装して提出したら400 Bad Request。すぐにm1のほうのサイトを開いて提出しなおしたところ、以前の提出もちゃんと処理されていたようでリサブ扱いになってしまった。最悪。

Cは難しい。a-bの累積和をSとすると、区間[l,r]S_{l-1}=S_rである場合のみ使用可能となる。さて、計算量的に左端からdpっぽいことをしたい気持ちになるが、区間のオーバーラップだったり操作の順序が顕著に関係してくるのが非常に辛い。ひとまず最も左端で使う区間[l,r]だった場合を考えてみると、S_{l-1}=0は最初から成り立っていなければならず、あとはそれまでの操作によってS_r=0になっている必要がある。そしてこのとき、l\le i\lt rに対してS_i\leftarrow 0となるようだ。

ここで、S_{l-1}=S_r=0であるような区間しか使えないと勘違いした。この条件を満たすような区間を使うと、それに含まれる位置のS0にセットされて使える区間が増え、最終的にSの全要素を0にできればYESと判定できる。結果的に正しかったが初期化ミスで1WAして本当に辛い。勘違いを修正する場合は、区間[l,r]を使うことがl\le i\lt rに対してS_i\leftarrow S_{l-1}=S_rとする操作であると捉えると、S0以外の要素を増やす利点がないことから結局S_{l-1}=S_r=0であるような区間しか使わなくてよいことが言える。

Dも難しい。cuteな数は、実験するとある正整数yについて[y^2,(y+1)^2-y)区間に入るとわかる。cuteな数の区間とそうでない数の区間は当然ながら交互に現れるが、その長さは先頭から順に2,1,3,2,4,3,\dotsとそれぞれで単調増加になっているようだ。ここから、a_1が属する区間を決めるとほかの数が属し得る区間が一意に定まる。つまり、a_1の条件から得られるkの候補が、それ以降でcuteでない数の区間を跨げるほど幅広くないということ。

計算の際は、逆にcuteな数の区間それぞれに対しそこに属する数を集めてみる。区間[l,r)と現在のkがあったとき、a_i+k\ge rとなるようなiの最小値は前計算しておけばO(1)で見つけられる。r-(a_{i-1}+k)-1がその区間だけ見たとき追加でkに足せる数となって、それのこれまでの最小値を求めておく。次の区間[l',r')についてa_i+k\lt l'となってしまうと困るので、先ほど計算した値の範囲内でkを適切に増やすことでa_i+k\ge l'とできるかチェックする。出現する区間の長さはa_1が属すると決め打った区間以上であるため、その長さがLのとき、探索する区間2\times 10^6/L個くらいになるとわかる。よって特に工夫せず調和級数になる。

残り4分で提出。しかし通らない。焦りつついろいろ書き換え、3WAしたあたりでコンテスト終了。システス後にテストケースを見ると、a_1が属する区間の候補をちゃんと検出できていなかったことが分かった。区間[l,r)に対してa_1\lt rならば候補とすべきところ、a_1\le lという条件にしていた。最初の提出からこれだけを修正したら通ってしまい、非常に悔しい思いをした。

コンテストの結果は3完70位で2953→2906(-47)。Bのリサブ扱いとCが解けなかったのでコンテスト中かなり絶望していたが、何とか2900は残して重傷に留めた。

しばらくYouTubeを見た後、午前4時から日記を書き始めた。木曜日の途中から書き始めたのに、今ここを書いている時点で午前11時。なぜこんなに集中できなかったのか。途中かなりの時間を、YouTubeを見たりハーメルンを読んだりするのに使っていたらしい。やるべきこともやりたいことも他に無限にあるはずなのに……。

見ていた動画をまた一つ貼っておく。「トンデモワンダーズ」で検索したら以下の動画が出てきた。これも木曜日に聞いていたのと同じくライブの切り抜きらしい。しかしダンスも歌も圧倒的。ホロライブとにじさんじの何が違うのかよくわかっていなかったが、ホロライブのほうはアイドルらしくダンスレッスンなど受けているということをコメント欄で知った。

「しかし」という言葉を使ったものの、別にどちらが動画として優れているという話ではない。木曜日に聞いていたのもまだ延々ループ再生を続けていて、これは社築さんと笹木咲さんの二人が歌って踊っていることに「良さ」があるんだよな。なるほど、これが関係性のオタクというやつか……。

www.youtube.com

日記を書き上げるともう正午近く。布団に入ってからしばらくカクヨムを読んで、午後1時就寝。

06/04(土)

午後4時前に生協の冷凍弁当を受け取った。正直起きられたのは奇跡だったと思う。眠りの淵でドアチャイムの音を聞き、しばらく何の音か考えていた時間があったように思う。

その後即座に二度寝し、次、午後7時前に悪夢で飛び起きた。人を殺してしまったという夢。犯行の瞬間ではなく、その後数年単位で時間をおいてから、幸せな日常の中でふと自分が人を殺したことを思い返し、捕まったら今の暮らしが全部崩壊してしまうのだと実感して震え上がるという夢だった。夢で本当に良かった。また三度寝。

午後8時にようやく起床。食事して午後9時からABC254。

AtCoder Beginner Contest 254 - AtCoder

Aは問題名から容易に内容の想像がつく。Vimで後ろ2文字を削除する方法を考えながら開くと、入力が3桁固定だった。つまり先頭1文字を削除すればよい。削除に1B、Vimの終了に2Bの合計3Bで書ける。16秒時点で提出したものの、最速は9秒で大敗。やはり問題ページを先に開いておく必要がありそう。Bはcombinationのテーブルを作る問題だが、念のためRubyやRakuの関数を持ち出さずにC++で問題文の式を書いた。CはK個おきに要素を取り出してソートし、全体をソートできているかチェック。

Dは数をsquare-freeになるまで割ったあと重複を数え、それぞれ2乗する。square-freeにする部分はi=2\dots\sqrt Nに対しi^2の倍数をループで列挙する方針。見るからに速そう。もうちょっと正確に評価すると、バーゼル問題より倍数を列挙するところまでは線形になっていて、実際に割っている部分がどうなるのかは謎。Eは次数もkも小さいので愚直に。Fは隣接項の差の区間\gcdを見るやつで、ただしA_{h_1}+B_{w_1}とも\gcdを取らなければならないのに気付かず1WA。差が全部0になる場合だけA_{h_1}+B_{w_1}を出力して満足していた。

Gは実装がヤバい。まずビルごとに区間が重なるエレベーターをマージしておく。ビルからビルへの移動がかなり自由であること、エレベーターが区間であることを考えると、わざわざ目的階から遠ざかるような移動をする必要はない。そして、前処理の時点で同じビルにいる間できるだけYWに、WYに近づけておくと、あとはどのビルからどのビルに移動したという情報を忘れてよくなる。すべてのエレベーターを使えると見なし、Y階からスタートしてW階より上(あるいはY\gt Wなら下)まで移動できた瞬間の、使ったエレベーターの数に1を足したものがビル間を移動した回数になる。

以下Y\lt Wとする。最初、Y階に対応するクエリを表す人がいるとして、下の階から順に見ていく。今i階を見ているとしよう。まず、i階がゴールであるようなクエリに対し、そのクエリを表す人が今どの階にいるかチェックする。ちゃんとi階より上にいれば、その人が使ったエレベーターの数を記録する。次に、i階にいる人をエレベーターに乗せて上に運ぶ。この時選ぶエレベーターは、i階から乗れるものであって最も上まで繋がっているものと決め打ってよい。そして、移動先にいる人とi階にいる人の集合をマージする。このとき、i階にいる人たちの使ったエレベーターの数にそれぞれ1加えておく。

集合のマージ部分をマージテクで行いたい。集合に属するすべての値について同時にカウントを増やすのは、代わりに全体に足されている値を持っておけば可能。残る問題は、クエリ番号からそれを表す人がどの階にいるのか取得すること。どの階にいるかではなくどの集合に属しているかを持っておけばマージはできる。ただしこの際、集合を単純に階の番号をインデックスにした配列で持ちながらうっかりswapしたりすると、クエリと集合の紐づけが外れてしまう。よって、集合を持つ配列は別に用意しておき、クエリ番号からも階の番号からもその配列を参照するという実装になった。ポインタでも良かったが慣れないので配列の添え字で押し通した。階の番号は集合に紐づけておけばよい。

実装が嫌すぎる。いったん順位表を見るとExのほうが解かれていてひっくり返った。まだ時間は結構あるのでじっくり実装し、何とか完成したものを提出。しかしWA。もう完全に嫌になってExを見に行ったがよくわからなかったので戻ってきて、デバッグを始めた。単純なケースで考察ミス、例えばエレベーターをマージする前に前計算してしまった値があったり、ビル間の移動回数を数え間違いしたりしたのが見つかって、さらにクエリと集合の紐づけを修正した4回目の提出が通ってくれた。地獄のような考察も、幸い大きな破綻なく実装しきることができていたらしく、軽微な修正で通ってくれて良かった。

もう一度Exを見る。大きな数から決めたい気持ちになる。実際、最大の数が一致しているならそれらをペアにすることで全く損しないことが言える。一致していない場合、大きな方を減らすことになる。それがA由来だったなら単に2で割って切り捨てればよい。B由来だった場合、これを2で割ることはAの要素を2倍することに対応しているので、奇数なら即座に-1を出力する。……もう解けているのではないか?優先度付きキューで適当に実装して投げたら通った。Gを通してからたった3分後であった。

全完7位。Gはダブリングらしい。完全に頭から抜け落ちていた。

直後、午後11時からGCJ2022 R3に出た。

https://codingcompetitions.withgoogle.com/codejam/round/00000000008779b4

Aはfunctional graphのループごとに塗り分けるとしてよさそうで、直感的にはループ上で隣接するものをさらに2個ずつ分けるのが嬉しいと思った。実装してローカルでテストすると、2ケース目から通らない。ここから解法ガチャを始め、いくつか全然ダメな解法を生み出した後3個ずつ分けるという方針を試したら全ケースに通った。そのまま提出してAC。正当性は謎。

Bは簡単。選ぶ区間の始点を固定して終点を数えたい。色ごとに選べる終点が高々2つの区間として表せ、全部の区間が重なっている位置の個数を数えられれば良い。後から始点をずらすことを考えれば、遅延セグメント木の区間加算で選べる終点に1加え、最終的に値がCになった位置を数える方針が立つ。区間加算を行いつつ値がCになった位置を数えるのは難しいが、これを「区間内の最大値の個数」と捉えると遅延セグメント木に乗る。典型。ちゃんと最大値がCであることをチェックしつつ答えに加え、始点をずらす際はその位置に塗られた色の条件だけ修正すればよい。A_i=0のケースでREを吐くも2回目の提出で通った。

Cはつい先週グラフ彩色の集中講義を受けた経験がダイレクトに表れた。まず、条件は高々(2+4)N個の「部屋uと部屋vは異なる文字でなければならない」という関係で表せる。このグラフを13彩色せよという問題になる。さて、今辺は6N本(以下)あるので、頂点の次数の和は12Nになる。これをN個の頂点で分け合っているので、グラフ全体の平均次数は12。平均次数は当然最小次数以上なので、つまりグラフには次数12以下の頂点が必ず存在する。そのような頂点一つとそれに接続する辺を削除したとき、残ったグラフについて、辺は高々6(N-1)本になっている。よってN\leftarrow N-1として最初の状態に戻ったとみなせる。このように頂点を減らしていき、グラフが空に(あるいは頂点数が13個以下に)なってから逆順に戻すと、戻す頂点は常に次数が12以下なので、他の頂点の色に依らずに必ず13色のうちどれかを塗ることができる。

この平均次数を用いる議論は、閉曲面に埋め込まれたグラフの彩色数を求める問題で嫌というほど触れた。オイラーの公式を使うことで、例えば平面的グラフならE\le 3V-6が言えるので、上の議論と同様にして次数6未満、つまり5以下の頂点が必ず存在するとわかる。したがって即座に平面的グラフが6彩色可能であることが言える。平面的グラフはさらに4彩色可能であることが知られているが、もっと種数の大きな曲面では、このような平均次数に関する評価だけで最良の彩色数を導けているということが示されたらしい。

ただし実装が下手くそ。いたるところにsetを使いまくるような実装でとりあえず提出したが、その後ランダムケースを試すと手元で50secかかっていることに気づいた。慌てて全体をvectorや優先度付きキューで書き直すと同じケースで6sec強になり、リサブした。

Dは何を考えればよいかすら全く分からず、残り1時間弱はABCのコードゴルフをしてしまった。結果はABCで30位。思ったよりdを通した人が多かった。Cで最初から高速なコードを提出できていれば、ペナ差でfinalに進めるくらいの位置だったようだ。恐る恐るリサブ前のコードを再度提出してみるとちゃんとTLEしてくれたので、決して無駄なリサブではなかった、というのは救い。僕は残りのグラフから次数最小の頂点を削除することに固執してしまったが、次数12以下であればよいので、普通にBFSっぽく書けるらしい。

ABCのコードゴルフ。AはFAの方もちゃんと3Bで提出しており、案の定負け。Bは配列をずらして和を取るようなコードをRakuで書いた。Cは元の列とソート済みの列でインデックス\bmod Kごとの値の(多重)集合が等しいか見たい。入る集合に応じて適当に係数を掛け、和を取って一致するか確かめる方針が短そう。単純にインデックス\bmod Kを掛けたら通った。飛んでExはheapq、Python3がTLEしたのでPyPy3。

Dは1\le i,j\le\sqrt Nかつ\gcd(i,j)=1なものに対しN/\max(i,j)^2の和を取るという方針が提出されており、美しく短かった。Octaveで書き直して最短に。しかしこれはどういう仕組みで数え上げているのだろう。見た瞬間納得した記憶があったものの、どうにも考え違いしていただけのようで、それほど簡単な話ではない。ちょっと詳しく見てみよう。

おそらく、組(i,j)をsquare-freeな数kx,yによって(kx^2,ky^2)と表した時のx,yについて全探索しているのだろう。ただし、上の解法ではkがsquare-freeであると限定されておらず、一方こちらは\gcd(x,y)=1である必要がない。ここがうまく対応づいていることを示そう。つまり、square-freeなkによる(kx^2,ky^2)と、\gcd(x,y)=1なるx,yによる(kx^2,ky^2)の間に一対一対応が存在することを見る。実は具体的に構成できて、前者の(k,x,y)があったとき、g=\gcd(x,y)として(kg^2,x/g,y/g)が後者の対応物になっている。逆に後者におけるkをsquare-freeにした分をx,yに押し付けると前者の組が得られて、これらは互いに逆写像の関係になっているので、よい。

別の問題のコードゴルフ。数の区間が与えられるので、それぞれ素因数分解して含まれる素数の(重複を含めた)個数が素数になっているものを数える問題。factor素因数分解してawkで出力を整えるのを2回繰り返していたので、evalとブレース展開を使いまとめた。このテクニックは何度か挑戦した記憶があるものの実際の最短コードにはなかなかならなかったので、こうして上手くいったのがうれしい。

atcoder.jp

レバガチャダイパンのこの回が面白いとおすすめされたので視聴した。序盤のバルーンファイトですでに面白かったので満足していたら、リズム天国が始まってからが本番だった。26分14秒のところで社築さんが椅子から崩れ落ちて座面を叩きながら笑っていたのが非常に面白かった。しかしリズム天国は難しそう。夜見れなさんのプレイの何が悪いのか、動画を見ているだけではよくわからなかった。自分の耳だけでリズムを取らなければならない点はノーツがある音ゲーと明確に異なる。音ゲーゴリラの社築さんもあまりスコアが出ていなかった。

www.youtube.com

https://youtu.be/rJNcd0c0JMk?t=1574

朝までカクヨムを読んでから日記を書き始めた。土日はコンテストが盛りだくさんなので、土曜日と日曜日の間にしっかり書き進めておかないとまた月曜日の昼までかかって日記を書く羽目になる。午前10時に書き終えて布団に入り、少しYouTubeを見て午前10時半就寝。

06/05(日)

午後3時半に親からの仕送りが届いて起床。なかなかスッキリした寝起きだったのでそのまま起きていることにした。しばらくTLを眺めて時間を潰し、午後5時からOpenCup。

今日はGrand Prix of Urals。チームとしてはEDMJALBGFCKをこの順に解いて11完12位。今回のセットは簡単な問題が多かったらしく、チーム共有ドキュメントに何も書かれず即座に倒された問題もいくつかあった。僕はAとFを解いた。

Aはマス目を連結になるように塗って、面積を周長で割った値がp/qと一致するようなものを構築せよという問題。実験して解いた。まずブロックがp個以上必要で、このとき周長は最大で2p+2になる。面積を増やしてもp/(2p+2)より比率を小さくすることはできないので、これよりp/qが小さければ構築不可能。それ以外のケースは全部h\times wのように配置するだけで作れるのではないかと思い、PCが空いた隙を見計らって試してみた。すると比率が小さいところでかなり抜けがある。そこで1\times w'のように伸ばすブロックを接続してみると、なんと全通り作れるようになった。

F。これからn日に渡って毎日一人ずつ人を働かせる。候補はm人いて、人ij日目に働かせるときのコストがc_{i,j}となっている。また、人iは連続してa_i日しか働けない。この制約のもと、かかるコストの最小値とそれを達成するような雇い方を求めよという問題。dpで解く。dp_{i,j}を「i日目まで終え、次の日人jを働かせられない状態」の最小コストと定義する。i+1日目に働かせる人を人kと決め打った時、それから人kを連続で働かせる日数を1\le d\le a_kとしてdp_{i+d,k}\leftarrow\min_{j\ne k}dp_{i,j}+\sum_{l=i+1}^{i+d}c_{k,l}と遷移する。

まず、値の取得は行の左右から累積\minを求めておけばよい。値の更新について、コストは累積和の形で書けるので、列ごとにみるとスライド最小値が使える。結局どちらも線形で行えるし、逆に制約がn,m\le 1500なので線形で行わないと間に合わないという問題だった。復元は気合い。

他にも読んだ問題がいくつかある。Bは貪欲で通ったらしい。こういう問題は貪欲が落ちがちという意識が先行して、それで通るという嗅覚が一切働かなかった。すごい。Cは特定の数だけ取り出してそれの遷移を見ると状態数がめちゃくちゃ少ない。これは気づいてもよかった。Gは全頂点の次数が3のグラフに関する問題で、何らかのグラフ理論的な背景があるのかと考えていたが、純粋に競プロ的テクニックだけで解けたようだ。Lはある関数の最大値を求める問題ではなく、値が適当な閾値を超えられるか判定せよと言われているので、その閾値を使って式変形していた。

前半で僕の貢献は終わりで、後半はIが実は愚直で通らないかなど無謀な実験をしていただけだった。

とりあえずここまでの日記を書いて、午後11時半からCodeChef。June Cook-Off 2022 div.1。

https://www.codechef.com/COOK142A

SIMPLE_XORは典型。(2n,2n+1)のXORが1なので、2つ束ねて0にする。

SPLITANDSUMは下のbitから見て、そこが立っている要素を数える。一つ以下ならその桁はより上に一切影響しないので無視してよい。二つ以上あった場合、和においてそのbitが立っているような連続部分列に分割できる。具体的には、偶数個だったら1個とそれ以外、奇数個だったら特に3個以上なので、1個と1個とそれ以外。しかしWA。何度考え直してもどこが間違っているのか全然わからず、ランダムケースでもちっとも落ちないので、とりあえず出力する区間が条件を満たすかチェックするassertを入れ、また配列サイズを念のため倍にして提出した。するとAC。

これは制約違反か?と思って運営にclarを出そうとして、ページをいろいろ探しているうちに、自分の最初の提出がいつの間にかACに変わっていたことに気づいた。特に通知もなくリジャッジが行われていたらしい。20分くらい時間を無駄にしてしまい、本当にキレていた。実はトップページにアナウンスが書き足されていたようで、そこを読むとチェッカーが間違っていたのが原因と分かる。いやこんなところ見ないって。

THROWTAKEはよくわからない。そもそも前の問題に信じられないくらい時間を使ったのを引きずっており、焦ってまともに考察できていなかった。偶奇を保ったままC3以下にしても答えは変わらないと信じ、メモ化再帰したら通った。後から試したら1以下にしてもよかったようだ。

PRFSUFDSTNCTは頑張って必要条件を探す。まずPSも隣接項の差に制限がある。またP_N=S_1である必要がある。以上が満たされていれば、Aに出現するP_N種類の数について、それらが出現する最も左の位置の集合と最も右の位置の集合が手に入る。これらをうまくマッチングさせる問題になりそう。とりあえず、集合の共通部分はそこに唯一出現する要素が入ることで確定する。残りはソートして先頭からマッチングさせていくのが最適で、区間の左右の大小関係が正しいことを確かめておく。

実はまだ足りない。P=\{1,1,1,2,2\}S=\{2,2,1,1,1\}の場合を考えると、マッチングまではうまくいくものの、真ん中に入れられる要素が存在しないことがわかる。つまり、上のマッチングで得られた区間に含まれないような位置があってはいけない。そういう位置は、左右でそれぞれマッチングが完結してしまっているので、今からペアを入れ替えたところでどうにもならない。よってチェックだけ行えばよく、いもす法で実装した。

一時50位台に落ちて絶望していたものの、ここまで解いた時点で10位台に戻ってきたのでまあ助かったかなという気持ちになって少し落ち着いた。

PERMSEGMENTSは難しい。挿入dpっぽいことをしたくなるが、隣り合うという関係が重要なので、(連続)部分列を作ってマージしていくという方針にした。小さい値から順に挿入していき、今持っている部分列はその直後に必ず一個以上、より大きな数を入れると定めておく。こうすることで値の挿入時に持っている部分列の個数がそのままその位置を含むような区間の個数となるため、条件のチェックができる。ただし、末尾に来る要素の取り扱いに注意。これのせいで区間の重なりのチェックが壊れるとまずい。よって、そのような部分列が存在するということを示すフラグをdpの次元に追加する実装になった。

値を挿入する際の方法は、前後に今ある部分列を入れるか入れないかで2\times 2通りあるので、それぞれ遷移を書き下した。この辺りは気合いでガチャガチャするしかない。前に部分列を入れて後ろに部分列を入れない遷移の際は、今挿入した値だけそこを含む区間が一つ増えてしまうことに注意。例えば2の前に[1]を繋げて、次に直後に3を入れると、2を含む区間が二個になっている。末尾に持ってくる部分列のチェックは、重なった区間の個数が条件を満たさなくなった瞬間に持っている部分列のどれか一つを末尾に固定して何とか回避するような実装をしたが、今整理して考えてみれば値を挿入するごとに末尾にするかどうか決めるほうがわかりやすい。コンテスト中の実装で重複が省けているのは結構非自明に見える。

MAXMINUSMINは実験。適当に回してみるとそのうち同じ値が2連続で出てきそうだったので、A=B\gg Cの場合にどういう遷移をするか手計算して、8ステップで似た形に戻ってきたのでそこをスキップする実装を行った。これでランダムケースに十分高速に答えられていたので、提出。しかしTLE。ここで、0\dots 10^{18}から一様に取ってA,B,Cとしていたランダムケースを、それぞれ10^6以下、10^{12}以下、10^{18}以下と決めるようにしたら、ちゃんとめちゃくちゃ遅いケースが見つかった。A,B\gg Cになったあたりで時間がかかっていたので、A\ge B\ge A-C\gg Cの場合を同様に手計算。するとこちらも8ステップで戻ってきて、先ほどのケースを含んでいることに気づいた。これを実装すると新しく作ったケースも高速になったので提出。自信はほとんどなかったが、通った。

6完6位で2708→2761(+53)。highestには1足りない。過去の自分が強すぎる。しかしリジャッジがあったが、このくらいのミスなら平気な顔してratedにするというのはすごいな。

社築さんが初のオリジナル楽曲を投稿されたので、今日はこれを作業用BGMにしていた。かなり良い。サイバー感のある歌声に編集されているのが好き。

www.youtube.com

午前5時前に日記を書き上げてからは、おすすめのなろう小説まとめを作成していた。↓の記事に追記する形でもよかったが、やはり時間の経過とともに過去の作品に対する印象が薄れてきて、今はそれほど心惹かれない作品も多く載っている。よって新しく記事を立てることにした。ただしここ1年で読んだ作品だけでなく、古い記事からもいくつか特におすすめしたいものを抜き出して載せる。わかりにくくなるとしてもオールタイム・ベストという体裁は保っておきたい。新しく増えたものだけ知りたい場合は各自で集合の引き算を行ってほしい。

進捗は、載せる作品の選定を終えて、各作品にコメントをつけている途中。それぞれ一言、自分が好きなところを書き留めている。参考にと読み始めて止まらなくなったりして、思うように進まなかった。

kotatsugame.hatenablog.com

午前9時を回ったので寝ることにする。

週記(2022/05/23-2022/05/29)

05/23(月)

日曜日、週記を投稿してからはすぐ布団に入って寝た。午前9時半だった。

午後3時起床。先週の週記に書いたように、今日はこれから大学で座談会に出席する必要があるため、インターン先の定例会で進捗報告ができない。よってスライドだけ作成して、事前に公開しておくことになる。その作業を起きてから行おうとしていたのだが、思ったより遅い時間まで起きられなかった。結構焦っていたつもりなのに諸々確認していたら完成まで30分以上かかってしまった。

急いで準備して出発。原付を飛ばしたら開始の5分くらい前に到着できた。生協に寄っている暇はなかったため、腹を空かせた状態で一時間ほど講演を聞いていた。座談会という名の通りそこそこ緩めの内容だった。細かい証明は明日からの集中講義で触れられるのだろうが、ちゃんと追うのは体力を使いそう。終了後に同級生数人で学食に向かい、僕だけさっさと食べて帰宅した。

家についてすぐ定例会に参加。自分の口から進捗報告する機会もあったので良かった。勉強会では発表後の質疑応答でいろいろ議論が活発に行われ、普段より遅めの時間に終了した。

そういえば、今日が締め切りの課題が2つあるのだった。終わらせにかかる。まずハードウエア基礎の課題で、ダイオードトランジスタの仕組みを問うようなものだった。特にトランジスタが大変難しく感じられた。講義資料とにらめっこして何とか今日の分は解けたものの、理解はできていない。

次にゲーム理論の課題で、これまで有限個の戦略を扱っていたところ、商品の価格や仕入れする数などで連続的な量を扱うようになった章の内容。表だったりゲーム木だったりを手書きする必要がなくなり、式を適当に弄くり回すことで答えが出るようになって書くのが楽だった。先手と後手のゲームを拡張し先手が親と子に分かれた場合を考察せよという問題があった。ターン数が3になって先手がもう一回行動するということか……?と思っていたが、講義動画をチェックして、親と子も別陣営と見なして先手が2人同時に行動を選択する場合を考えていると理解した。同時手番と逐次手番を組み合わせたゲームを扱おうという意図だろう。

合間で一瞬だけインターン関連の作業、ドキュメント整備をした。前に書いた版では特に意識せずディレクトリという言葉を使っていたのに気づいた。フォルダーと言わないと一般には通じなさそう。

何とか課題を終わらせられたので、午後11時半からECR129に出た。

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

Aは手持ちの最大値を初手で出すのが最適。それぞれの最大値を調べて、先手が後手以上だったら先手勝ちになる。Bはただrotateを繰り返しているだけなので、操作を全部まとめて\left(\sum b\right)\bmod n回rotateすることになる。Cは一致する値の処理が面倒。先頭からソートされた列を構築していくのが簡単そう。ソートされていない部分の\minをそれぞれ計算して、(\min a,\min b)というペアを探し手前に持ってくるのが良い。

Dは大変。桁数と出現する数字の集合のペアを状態として達成可能な最大値を求めるBFSをしたら落ち、操作回数を加えてdpに書き直したらpretestは通った。しかし後からHackされた。当たり前で、掛け算した後どのような数になるかが異なるのに状態をまとめてしまってはいけない。正しい解法は、作れる数がx\times 2^{e_2}3^{e_3}5^{e_5}7^{e_7}という形をしていて十分少ないため、普通にBFSするというもの。

Eは面倒。レイヤーの番号が大きくなる方に移動することを考える。「レイヤーiのドア1,2からレイヤーi+1のドア1,2に行く距離」を2\times 2行列で持つとdpがトロピカル半環上の行列積になるのでセグメント木に乗るといういつものやつ。ドアそれ自体が「レイヤーの間」を表すのに、さらにドア間の移動、いわば「レイヤーの間の間」を扱うため添え字にはかなり注意が必要だった。しかも行列積の単位元を間違えていてデバッグにかなり時間を使った。

Fは全方位木dp。各辺(u,v,x)について、「uから見たvの部分木でvから値xの辺を使わずにたどり着ける頂点」と、そのuvを入れ替えたものが計算できれば良い。適当に根付き木にして、uvの親になったとしよう。各値yに対し「vの部分木で値yの辺を使わないとたどり着けない頂点」の数を求めようとしてみると、mapとマージテクで計算できることがわかる。xに対するカウントをvの部分木のサイズc_vから引くことで、求めたいもののうち片方は求まった。

もう片方を全方位木dpで求める。最初のDFSが終わったとき、各値yに対し「根から値yの辺を使わないとたどり着けない頂点」の数が求まっている。これの根を取り換えながらもう一度DFSする。辺(u,v,x)を使ってuからvに降りる際は、値xに対するカウントだけ変更すればよい。vの部分木に限定した値は一回目のDFSの時点で記録しておけて、残りのvから見てuの先にある頂点たちは全部(u,v,x)を使わないとたどり着けないので、n-c_vを足す。このテーブルと先ほど求めた値さえあれば答えはすぐ求まる。

最後のn-c_vを足すあたりの考察で、辺(u,v,x)についての「uから見たvの部分木でvから値xの辺を使わずにたどり着ける頂点」が結局「vから値xの辺を使わずにたどり着ける頂点」であったということに気づいたが、いずれにしても全方位木dpをするためには最初のDFSで前者の値を求めておく必要がある。

火曜日提出の離散数学の課題も終わらせた。特筆すべきことはない。

朝まで日記を書いていた。布団に入ってしばらくハーメルンを読み、午前8時ごろ寝落ちした。

05/24(火)

午後1時半起床。今朝読んでいたハーメルンの最新話に追いついた。

syosetu.org

実況パワフルプロ野球20xx 「球界の至宝」取得RTA投手チャート」。「ソードアート・オンライン ラフコフ完全勝利チャートRTA 2年8ヶ月10日11時間45分14秒(WR)」を書いていた方の新作。主人公の性格はそちらと変わっていないようで、冷徹さというか、人の感情を計算に入れない行動がやはり好みだった。前作は主人公が悪人側だったので、いずれ訪れる崩壊への恐怖で心の底から楽しめていたわけではなかったが、こちらはそんなこともない(し、そもそも原作を知らない)ので非常に面白かった。

一旦購買に行ってお菓子やパンとラノベを購入し、帰宅。食べてまたすぐ家を出て、今度は山に登った。いよいよ集中講義一日目である。学部時代には集中講義というものを受けたことがなく、たった一週間で一セメスター分の学習時間を要請するのだから長い間講義漬けになるのだと思っていたが、予定では午後3時から3時間だけらしかった。

講義。今日は一般のグラフについて用語を定義したり、性質を示したり。平面グラフを扱う講義ではあるが、それに特有の性質までは踏み込まなかった。特に後半では、どんなグラフでも次数が奇数の頂点は偶数個存在するという事実を用いて、いくつかのパズルをうまくグラフに言い換えて解いており、面白かった。この事実には「奇点定理」という名前がついているらしい。当たり前の事実ながら応用の幅はかなり広いようだ。

n頂点のラベル付き単純グラフは何種類あるかという問題があった。競プロをやっていれば一瞬で2^{n(n-1)/2}とわかる。誰も答えなかったので勇気を持って発言したら褒められて、かなり良い体験だった。ちょっと子供っぽいか?ともかく、今日はそうやって真剣に講義に参加していて、他にいくつか質問したり指摘したりしたのも楽しかった。こんなにのめり込みながら講義を受講したのはいつ以来か、学部時代よりさらに昔である気がする。講義の内容が自分の興味に概ね一致していて、かつ対面で参加できたのが大きい。

午後5時には終了。予定より早く終わったのについて講師の方に聞いてみたのだが、一日2時間のつもりで準備してくれ、と言われていたらしかった。3時間とは質疑応答を含めても余裕のある予定だったようだ。

今日は昼にミールカードを使い切っていたので、そのまま帰宅。しばらくグダグダTwitterを眺めてから出発し、午後7時くらいにゲーセンに行った。

途中夜ご飯のために離脱しようかなと思っていたが、かなり上手い日だったので眠気で鈍らないようにとそのまま閉店まで遊び続けた。今日の成果は理論値7譜面、14+のSSS1譜面、SSS+1譜面。

曲がかなり好きでしばらく前にも狙ったものの、中盤のハネリズムがボロボロだったのですぐ諦めた記憶がある。ハネを意識しすぎた結果むしろ微ズレのような押し方になっていると気づいたので、今日は早め早めを意識してみたところ、なかなか上手く行った。あとは最初と最後に何度も降ってくる階段も含めた噛み合い待ち。一つ一つはそれなりの確率で通るが連続して来るのですぐ崩れてしまい、かなり苦しかった。ちゃんと決めきれたのは嬉しい。

これまでは最後の左右に振れるトリルが全然できなかった。脱力を意識しスライダーを叩いた時の反動だけで手を浮かせるような感覚でやってみると、速度的には十分間に合うし、力んでいないので手を左右に動かすのも簡単。今日一発目でニューレコードが出たので、SSSを狙うことにした。そのトリルもたまに酷い失敗をしてしまうので、結局これも噛み合い待ちになる。最終的にはなかなか高いスコアが出たと思うが、ここまでくるとSSS+欲しかったなという気持ち。107小節から118小節で0-2出していて、その部分は今もよくわかっていない。

上手い。間違いなく。

追加されたのが旧筐体のラスト。最後を全押しして3kに乗せ、むしろ前半が全然できなかったので放置した。その後新筐体になると最後の全押しが全然通らなくなってしまった。これはfpsが倍になったことによるのだろうか?ともかく、全押しで通らないならもう伸びないだろうなと半ば諦め気味だった。ところが最近になって何回か触ってみて、前半……というかラストまで普通にSSS残せるようになったと気づいた。特に運指を組んだわけでもなく、シンプルに押せるようになっていたということ。

14+の最後の一つとなったので、今日改めて譜面を確認しながらプレイしてみた。まず45、46小節と85、86小節。指押しからタップスライドに切り替えるタイミングを間違えることが多かったので、それぞれ一回目より二回目のほうが少し指押しが長いことを覚えた。もともと四鍵固定で押せていたので、なかなか安定するようになった。またその直後、それぞれ48小節と88小節はどちらも右手トリルと左手8分で押すことにした。後者は直前の指押しからそのまま入ると左手トリルすることになるので注意。

あとは最後。3小節の指押し地帯が二回降ってくる。このうちの前半は軽傷で済むことが多かったので、いったいなぜ押せているのか確認したところ、真ん中のノーツまで右手を動かして取っていることに気づいた。これが左右反転した後半は、左手が右手に比べて弱いせいでボロボロになってしまっていたらしい。なので、後半も右手を酷使することにした。それでプレイしてみるとまあまあ改善されて、両手トリルの入りも確認しないとと思っていたところで急にめちゃくちゃ噛み合い、上に載せたような2-0という信じられないリザルトが出た。記憶では48小節の終わり際と、102小節でそれぞれ出したはず。最後、無我夢中でやっていたらスルッと通って本当にびっくりした。

残り時間は適当な14+を触って終了。Ai Novの鍵盤も見えるようになっていて感動した。一番町で酔っ払いに混じってラーメンを食べ、帰宅。疲れ果ててしばらくYouTubeを眺めながらボーっとしていた。

www.youtube.com

そのうち少し眠ってしまったので気合いで起きてシャワーを浴び、ラノベを読み始めた。明日はこのくらいの時間からCFがあるので、敢えて生活リズムを崩壊させておく必要がある。

「お隣の天使様にいつの間にか駄目人間にされていた件」6巻読了。この巻は徹頭徹尾主人公とヒロインがイチャイチャし続ける巻だった。ストーリー的に進んでいるのかはよくわからない。僕は両想いのカップルがイチャイチャするシーンというよりも、その結果人前でも二人だけの空間を作り出してしまうようなシーンが好きなので、前半は正直あまり楽しめなかった。後半は夏祭りに出かけていたので個人的に美味しい展開だった。

またしばらくYouTubeを見てから午前8時就寝。

05/25(水)

午後2時起床。

先日本番環境にデプロイされた機能がブラウザで表示されないというメッセージが来ていて一気に目が覚めた。実は自分の普段使いしているPCでも同様に見えていなくて、PCを変えたりスマホからだと見えるのでいいやと思っていたが、それは実際の使用者にとって解決策にはならないわけだ。キャッシュの問題だろうと当たりをつけてスーパーリロードしてみるも効果はなく、デベロッパーツールのほうからClear site dataを行うと見えるようになった。スーパーリロードと何が違うのかよくわからない。設定からまとめてキャッシュを消したらどうなるのだろうか。とにかく、こうすると対処できましたということを伝えておいた。

講義開始まで時間がない。ブラックサンダーを一つ食べてすぐ山に登った。

講義。今日はグラフ理論におけるオイラーの公式を示して、それを用いて平面グラフの辺の数を評価したり、正多面体を列挙したりした。また、平面グラフの特徴付けとして、K_5K_{3,3}をマイナー(あるいは細分に限定してもよい)として持たないことが紹介された。さらに、多面体から作ったグラフの全域木と多面体の展開図の対応についても話された。ラベルなしの全域木を数え上げるのはかなり難しい話らしい。競プロで木を数え上げると聞くと行列木定理やケイリーの公式を思い浮かべるが、確かにどれもラベル付きであって、単純に階乗で割ったりしても全然見当違いの値が出てきてしまう。

学食で食事して帰宅。しばらくTwitterをしていたがどうにも眠い。深夜のCFに向けて念のため目覚ましを設定したら、その直後うっかり布団に倒れこんで寝落ちしてしまった。午後7時半から午後11時半まで寝ていた。

起きてからはラノベを読み、午前2時半からCF #794 div.1。

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

Aは、まずnが奇数の場合は不可能。偶数の場合はとりあえずソートして、前半を円環状に並べた間に後半を置くのがよさそう。a_{n/2+1}a_1a_2の間に置くか、a_{n/2}a_1の間に置くかで2通り考えられる。前者で破綻する場合を注意深く確認すると、最小または最大の要素がn/2個より多くある場合と、それ以外の要素がn/2個以上ある場合がまずいようだ。後者はa_{n/2}=a_{n/2+1}の場合即座に破綻してしまい、これは前者で破綻するケースを完全に含んでいる。よって前者で構築するほうが良い。さらに、ある要素がn/2個存在するとき、それを一つ置きに配置するしかないということを考えると、前者で構築できないパターンは全部不可能と分かった。

BはABの文字数を数えてチェックしておくと、ABBAを使い切る問題になる。文字列を同じ文字が隣接する場所で切っておくと、それぞれがABAB...BABA...になる。この長さlで用途を分ける。lが奇数の場合は、ABBAをどのように切り出しても合計で(l-1)/2個になる。lが偶数の場合は、対応するABまたはBAのみを切り出す場合だけl/2個となり、逆のタイプを少しでも切り出そうとすると合計(l-2)/2個になる。つまり、ABBAはそれぞれ対応する偶数長の文字列→奇数長の文字列→対応していない偶数長の文字列、の順で切り出していくのがよい。特に、対応していない偶数長の文字列から切り出すときは、長さが長いものを優先的に使うべきであることもわかる。

Cは初手がわからず結構悩んだ。いつもの\pm 1累積和がreverseでどのように変化するか確かめてみると、\dots,S_l,S_{l+1},\dots,S_r,\dots\rightarrow\dots,(S_l+S_r)-S_r,(S_l+S_r)-S_{r-1},\dots,(S_l+S_r)-S_l,\dotsになると分かった。Sが負になる項を全部含み、かつS_l+S_rが最大となるようにl,rを定めるとき、S_0=S_{2n}=0なので必ずS_l,S_r\ge 0とできる。操作後、もともと負だった位置は必ず正になるので、問題はS_m=\max_{l\le i\le r} S_iについて。S_l+S_r\ge S_mの場合はこの1手で累積和を全部非負にできる。ではS_l+S_r\lt S_mの場合は……なんと、(l,r)\leftarrow(l,m),(m,r)とすることで2手で必ず可能。あとは累積和のインデックスを文字列のインデックスに直して出力。

D1は簡単め。q_i=p_{q_{i+1}}となるように並べるのが一番嬉しい。つまりpの逆順列p^{-1}を用いると、q_{i+1}=p^{-1}_{q_i}としたい。i\rightarrow p^{-1}_{i}という辺を張ったグラフが一つの大きなループになっていればそれが達成できるが、一般にはいくつかのループに分かれてしまうので、できるだけコストをかけずにマージせよという問題になる。1を含むループを元にし、現在のループに含まれない最小の頂点iを取り、それを含むループを現在のループにマージしていく。このとき頂点i-1は必ず現在のループに含まれ、特に構成方法から次の頂点がp^{-1}_{i-1}になっているので、その間にi-1\rightarrow p^{-1}_i\rightarrow\dots\rightarrow i\rightarrow p^{-1}_{i-1}と挿入すると、コストの増加を|(i-1)-p_{p^{-1}_i}|+|i-p_{p^{-1}_{i-1}}|=2だけに抑えつつマージできる。マージするとき2か所以上繋ぎ変えるためコスト2は必ずかかりそうなので、これが最適っぽい。

n\le 200なのにO(n)で解けてしまって大変怖い。D2はqを辞書順最小にせよという問題で、先頭の項からO(n^2)回かけて決めつつD1を応用してチェックをO(n)で行えば解けると思った。しかし実装が爆発し、コンテスト終了。

システスは全部通って22位。D1とD2の間の崖が大変大きかったようだ。変な時間のコンテストということもあり人が少なく、この順位でもレート変動は2916→2953(+37)。あと1、2回勝てば伝説に手が届きそうなレーティングまで戻ってきた。頼む。

コンテスト後はまたラノベを読んでいた。午前7時半ごろ布団に入り、さらにハーメルンやなろうを読んで午前9時就寝。

05/26(木)

午後1時半起床。あまりにも眠すぎてグダグダTwitterするのが精いっぱいだった。午後2時半前に家を出て、購買でパンとラノベを買い、今日はそのまま山に登って講堂のロビーで食事した。

講義。いよいよグラフの彩色の話が始まった。五色定理の証明が紹介されて、そこから四色定理の誤った証明が述べられた。さて、どこが間違っているでしょう……ということで、競プロで培ったコーナーケース発見力を発揮しようと熱心に考えていたのだが、数分でスライドが進められてしまった。結局、着目していたポイントは悪くなかったものの、スライドに描かれた図に思考が誘導されていたので、別に惜しくもなかった。これを「誤っている」と知らない状態で見つけるのは確かに偉業と感じられる。

五色定理 - Wikipedia

平面グラフの彩色は前半で終わってしまい、残りはもっと種数が大きな閉曲面での彩色数の話に発展していった。想像するのが難しくて直感が働かないし、変なコーナーケースがいろいろあるしで難しい。

午後6時帰宅。適当な時間に学食に行くつもりだったが、ラノベを読んでいたら行き損ねてしまった。そのまま読み続けて1冊読了。

デート・ア・ライブ アンコール」11巻。やはり良い。大学生になった組も高校生になった組もそれぞれフォーカスされた短編があって、大変満足のいく巻だった。まだまだ読み続けたいが、後書きを読んだ感じ、まだ未収録の短編が残っているものの次の短編集が刊行されるかは未定らしい。確かに、新シリーズも抱えていらっしゃるのに完結したシリーズを延々擦り続けるのは、新規のファンが増えず作家としては良くないのだろう。

この前のあーだこーだーで面白かった本として「儚い羊たちの祝宴」をお勧めしたら、読んでくださった方がいらっしゃったらしい。大変ありがたいことである。

ラノベをもう1冊読了。「僕たち、私たちは、『本気の勉強』がしたい。」。かなり面白かった。チラシや通販サイトでは作中の「才能がなくても東大に入れる」というセリフを引用して紹介されており、過激な作品という印象が先行していたが、実際読んでみると地に足のついた勉強方針が描かれているなと感じた。そして、そういう描写を受け入れてみればストーリー的にも十分面白く、主人公が勉強にのめり込んでいくシーンの一人語りは読んでいて心を動かされ、じっとしていられなくなるような気分になった。

朝方、少しだけ集中講義の課題を進めた。講義スライドの途中で出てくるたび、頭の中で解けることを確認してはいたのだが、対面で質問できる機会は明日が最後なので、本当に疑問点がないかもう一回チェックしようと思っていた。結局記述の面倒くささが勝って、また頭の中で解ける解けると思うだけに留まってしまった。

ラノベを読んで午前9時就寝。雨が降っていて、明日の登校が憂鬱。

05/27(金)

午後2時起床。あまりにも眠すぎる。また生協に行く時間がないので、カロリーメイトが昼食となる。

地面が濡れているので雨が降っているのだろうと考えカッパを着て、さあ出発だと外に出たら、ちょうど晴れ間の時間帯だった。部屋に戻ってカッパを脱ぐ。帰るころには降水確率10%になっているので必要ないかとも思ったが、念のためリュックに押し込んで再度出発した。

講義。この一週間の睡眠不足が祟って耐え難い眠気に襲われ、前半は意識を飛ばしがちだった。非常に残念。いや朝までラノベを読んでいたのは自分なのだが……。ただでさえ初めて触れることばかりで難しいのに、少し聞き逃してしまい、理解があいまいな部分がある。

今日は昨日の後半の続きで、種数が大きな閉曲面に埋め込まれた特殊なグラフの彩色数。正直な感想としては、そんな特殊な場合の話をされても、というような定理たちであったが、その証明手法は非常に面白かった。気合いで塗り替えてみたり、謎の値を2通りで評価してみたり、代数構造と対応させてみたり。グラフの生成定理も出てきた。僕が少し前に読んでいた論文もグラフの生成定理だったので興奮した。

四色定理がコンピュータによって証明されたということを知ってはいても、コンピュータが一体何を計算したのかは知らなかった。実は四色定理もグラフの生成定理を用いて示されたらしい。平面の三角形分割は一種類の変形のみでK_4に帰着できるものの、これだと変形を逆に見たときに彩色数を保てないので、ちゃんと保てるように変形を複雑化させて個々のケースをコンピュータで処理したということのようだ。どこかで「四色定理を示すには有限個のパターンについてだけ塗り分けられればよいことが分かった」という文章を読んだ記憶があって、ずっとグラフの一部を取り出したパターンが有限個しかないということだろうと思っていたのだが、確かに、それではローカルに塗り分けられたとしてもグローバルに整合性が保たれるかはわからない。

講義を終えて、同級生数人と学食で食事。カレーの中サイズと丼の中サイズを注文して、一人だけフードファイトしていた。カレーが大変辛かった。満腹中枢が反応する前に食べ切ろうと可能な限り急いだ結果、他の人と同じくらいの時間で完食した。

その後道端で3時間ほど喋っていた。4年ゼミで一緒だったのが大学院に入って研究室が変わった結果顔を合わせる機会が極端に減ってしまったので、名残惜しむように話題が途切れなかった。実際は途切れても無理やり話し続けたというのが正しいか。いろいろなことを数学にこじつけて話していた。煩悩は108個あるとされているが、2^2\times 3^3素因数分解できることに意味はあるのかなど。検索してみると6\times 3\times 2\times 3と分解されていて、みんなしてへえ~と言っていた。

午後9時を回って帰宅。しばらくニコニコ動画を見た後ふらっと布団に倒れこみ、即座に寝落ちした。午後10時半から午前4時まで寝ていた。

起きてからはまたニコニコ動画を見たりラノベを読んだりした後、日記を書き進めた。月曜日に書いてからずっと溜めてしまっていた。午前10時に再度就寝。

05/28(土)

午前11時55分に目覚ましで起きたはず。正午からAHC011が始まるので、Shortest狙いでできるだけ早く問題文を読もうとしていた。しかし実際は布団から身を起こせず、ハッと気づいたら正午から10分経過していた。慌てて読んで提出。このあたりのことは、一応この頃の順位表から読み取れるはずなので、コンテスト終了前に公開される日記に書いてもよいはず。

再度就寝。午後4時前に冷凍弁当を受け取り、また眠って、午後7時に起床。日記を書いて時間を過ごし、午後9時からABC253に出た。

NOMURA Programming Contest 2022(AtCoder Beginner Contest 253) - AtCoder

AはとりあえずAWKで書いた後dcで縮めた。結構時間をかけてチェックしていた。BはC++で素直に。Cはmultiset。Dは全く同じ問題を見た覚えがあると思って、{\rm lcm}が書きやすいRubyを持ち出した。しかし再現したコードとサンプルが合わないのを見て、前の問題では個数を求めていたのに対しこの問題は総和を求める必要があることに気づいた。包除原理という方針は同じなので、少し書き換えるだけでよい。Eはdp。Fは行と列それぞれ持つだけで終わりかと思ったら、行の書き換えの時に列に足されていた値も考慮する必要があった。取得クエリの直前の書き換えクエリを見つけて、その位置でも列の値を取得するようなコードを書いて通した。最初にi=1\dots Nに対し(2,i,0)というクエリを用意しておいて、クエリを逆順に見る実装をした。

Gは簡単。x=1\dots Nに対し操作を行う(x,y)を列挙すると、y区間になっている。その区間が最大、つまりy=x+1\dots Nのすべてで操作が行われるなら、まとめると列の後ろN-x+1要素のrotateになる。そうでない場合は操作を愚直にシミュレートしても合わせてO(N)である。x=1\dots Nのそれぞれで操作し終わるたびに先頭x項が決定するので、列をdequeで持って毎回pop_frontすることにすれば、rotateも末尾からpopして先頭にpushするだけで書ける。

Exは、K本の辺をループができないように選ぶ場合の数を求めてK!/M^Kを掛けると答えになる。選んだ辺の本数は操作後のGの連結成分数から復元できるので、どのような連結成分を作るかで3^NのbitDPを行う方針が立つ。すると、頂点の部分集合すべてについて、それを木にするような辺の選び方が求まればよくなる。一瞬元の問題と同じに見えてしまったが、「森」であった部分が「木」になっているのが違い。つまり全域木を数え上げることになって、行列木定理で一発である。

ノーペナ全完で3位。数学を専攻する学生でもあることだし、これまで経験がないくらい大量に賞金が貰えそう。かなり多くの人がEのK=0でペナを出していたらしい。自分は書きながら気づいて、dpの枠組みで対応するのも面倒だったので即座にM^Nを出力するようにしていた。

コードゴルフ。Aはdcが1B縮んだようで負け。BはPerlshebangを使ってうまく書けた。for/o/gでループすると、同じ行に二つ'o'がある場合に二つ目の情報だけ取得してしまうが、ここをwhile/o/gにするとうまくいくようだ。しかし文字列にマッチした位置のオフセットを取得するところで@+@-が使えるのを完全に忘れており、負け。Dはdc、GはRuby

CはC++でmapを使う。まず僕が書いて、それがどんどん縮められて、ちょっとした隙をついて今はまた僕が最短コードを持っている。この問題のように複雑な形式のクエリをscanf一発で読み込む手法が出ていて、かなり興味深かった。単に"%d%d%d"と書くと次の行まで読まれてしまうし、これを"%d %d %d"としたとしても、スペースの部分で任意の個数の「空白文字」、つまり改行も読まれてしまい先ほどと状況は変わらない。ここでスペースのみを読み込むように指定できれば、そこに改行が来た場合何も読み込まずに止まってくれて、次の行を読むのを抑制できる。文字集合の指定によって実現され、今回の場合%[ ]になる。読み捨ての記号*を追加して、以下の提出のようなフォーマット文字列が得られる。

Submission #32068201 - NOMURA Programming Contest 2022(AtCoder Beginner Contest 253)

C言語入門 - scanf関数 - スキャン集合を使った文字列 - ホワイトスペース - Webkaru

午前1時からSRM830に出た。

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

Easyはちょっと面倒なdijkstra。pitsを踏んだかどうかだけフラグで持っておく。

Medはdp+復元で、復元部分が面倒。モールス符号は問題文からコピペして、先頭と末尾に"を付け加えて文字列の配列に変換した。Vimのビジュアルモードで一発。構文をしっかり解釈すると、文字を|または||で分割していればOKということがわかるので、直前が文字であるかセパレータであるかの2状態を持っておくだけで十分。これで変更する文字数の最小値を求めて、逆から辿っていく。2状態を取り違えまくって実装に苦労した。逆から辿るときは完全に正しいコードを書かないとすぐ遷移元が見つからなくなって無限ループしてしまうので、テスト実行の待ち時間が煩わしかった。無思考でBatch Testを連打するのも考え物。

Hardは実験+エスパー+埋め込み。(R,B)をいくらか計算して出力し睨みつけたところ、縦にも横にも倍数の関係があることが見て取れた。B\le 1の場合(R,B)=(1,0),(0,1)以外全部0なので別に計算することにして、B\ge 2とすると、まず(0,B)(2B-3)!!で表せている。さらにそこから下にR回進むときは、B-1倍、B倍、……と増えていたので、\prod_{i=1}^R(i+B-2)を掛ける。これでテーブルを再現できるはず。

\bmod{10^9+7}なので、2B-3\ge 10^9+7のときの値は0。そうでないとき、(2B-3)!!=\frac{(2B-2)!}{2\cdot 4\cdot\dots\cdot(2B-2)}=\frac{(2B-2)!}{(B-1)!2^{B-1}}\prod_{i=1}^R(i+B-2)=\frac{(R+B-2)!}{(B-2)!}と変形すると、どの分母も\bmod{10^9+7}0にならないのでちゃんと計算できる。あとは階乗を高速に計算するだけ。高速階乗なんていうライブラリがどこかに落ちていたはずと思って探してみると、畳み込みを使っていて大変そうだった。yukicoderにそのままの問題があって、過去の自分が埋め込みで通していたので、これをコピペしてきた。適当に大きめのケースを試すと少しTLEしてしまったので、埋め込む間隔を10^7から3\times 10^6に書き換えておいた。

#164690 (C++14) No.502 階乗を計算するだけ - yukicoder

Easyで古い問題文が表示されていたらしく、システムテストに更新後の制約である100\times 100の入力が含まれていたようだ。後からリジャッジされるらしい。僕もEasyが落ちてしまっていたが、MedとHardは通ってくれて3位になっている。僕より上にいた人が何人かHardを落としているので、Easyのリジャッジが行われた後もかなり良い位置につけているのではないかと期待が持てる。

Hardの証明は、集合の分割を二分木として見るとよいらしい。まずBだけで分割方法を考えると、B-1個を分割する二分木のどこかのノードに1個子を生やすことになって、木のノードは分割のために縦に伸びた分も含めて2個増える。つまりB-1個追加時点では2B-3個のノードがあり、そこから1つ選ぶ方法だから2B-3を掛けることになる。B=1に帰着されるまで辿ることで(2B-3)!!が得られる。あとはRを追加する方法で、(R,B)=(1,0),(0,1)以外のノードに1個子を生やせるので、追加するたびに使えるノードが1個増え、i=1\dots Rに対し(2B-1)-B+(i-1)=i+B-2通りとなる。

ラノベを1冊読了。「好きで好きで大好きなので、いっしょに好きを伝えたい」。ヒロインがVtuberをしているらしいので購入。しかし別にVtuberをメインにしているわけではなさそう。少なくともこの巻は主人公とヒロインの馴れ初めを描くのに紙幅を費やし、Vtuberをしている描写は冒頭とラストに少しずつ現れるだけだった。そのラストの部分でVtuber活動に影響を及ぼすような出来事が起こるので、2巻ではよりクローズアップされるものと思うが、結局Vtuber活動を通してヒロインを描くだけで、舞台装置の一つ以上の役割にはならないだろうと予想している。

それから朝まではずっと日記を書いていた。午前10時就寝。

05/29(日)

午後3時半起床。食事して午後4時からOpenCup、の代理のコンテスト。先週と同じで、通常のOpenCupがない週のためadminから配られたコンテストにバーチャル参加するやつ。午後9時からARCがあるので、それに被らないような時間から開始するということでチームメイトと合意していた。今日のコンテストタイトルはPKU Contest 1, PTZ Summer 2021 Day 4。

チームで5完。自分はAとFを担当した。Aはひとまず重複してカウントするような辺を許して数え、後から間に辺が存在するような頂点対の分だけずらす。数える部分は畳み込みの形になるので、convolution_llを使う。順位表では結構ペナが出ていたようだったが一発で通った。自己ループの処理に少し気を使ったので、そこで間違えた人が多かったのだろうか?Fはrange addとrange chmaxで実家dpができる。制約が2\times 10^5でTL 1secと設定されており、beatsの定数倍が悪いこともあってかなり不安になったが、OpenCupなら通るだろうと強く主張した。ライブラリを持っていないのでチームメイトの全部盛りbeatsを拝借してそのまま出したら0.9secで通った。持つ情報をもう少し絞ればもっと速くできるだろう。

残り時間はHとBで半々くらい使った。Hは結局解けず。Bはカクタスグラフを扱う問題で、紙の上ではできているものの実装に失敗という感じ。ループの繋がり方を見るためにBlock Cut Treeを持ち出してガチャガチャしており、何回か提出して全然通らず、この先合わせられる自身がなかったので別の問題のためにPCを譲った。その問題はコンテスト終了8分後に通っていた。ちょっと申し訳ない。

午後9時からARC141。

AtCoder Regular Contest 141 - AtCoder

Aはとりあえず9の連続が作れて、それより大きな数は桁数がNと同じになるので、mの桁数を全探索するのが良さそう。mとしてはNの先頭から取ったものをそのまま使うか、1だけデクリメントしたものを使うかだけ考えれば十分。Bは簡単。B_i\lt B_{i+1}という条件からA_{i+1}のMSBがB_iにおいて立っていないことが言える。さらにA_i\lt A_{i+1}よりMSBの位置は単調増加なので、特に狭義単調増加になる。それより下のビットは自由に決められるので、MSBの位置を添え字に持つdpを行えばよい。N\gt 60の場合答えは0なので、先に弾いておく。

Cは信じられないくらい難しかった。とりあえずPから取り出せる限りの情報を取り出してみる。まず、S_{P_1}'('であり、それより前の文字はすべて')'でなければならない。今決まった')'を使い切るより前にSのもっと先の要素を使う場合は、それもまた'('であるとわかり、P_1との間がまた全部')'とわかる。このようにして、\max P_{[1,i]}=iであるような位置までは完全に決定してしまう。ではその次の文字はどうなるだろうか。P_{i+1}=i+1である場合は、正しい括弧列になる限り何でもよい。\max P_{[1,i+1]}=i+1が成り立っていれば、という風に見ることもできる。P_{i+1}\gt i+1の場合、i+1番目には')'が使えなかったとわかる。つまりS_{P_{[1,i]}}だけを見たとき、そこで完結した正しい括弧列になっていなければならない。そのあとはP_1以降の議論の繰り返しになる。

まとめると、\max P_{[1,i]}=iであるような位置で分割したとき、長さが1より大きいブロックと先頭のブロックは完全に決定し、またそれらの直前までが正しい括弧列になっていることも要請される。Qについても同様の処理を行って、2通りの文字列が完成した。Q_i\leftarrow 2N+1-Q_iとしてPに対するものと同じ処理をしてから反転するのが楽だった。

この2通りの文字列をマージしたとき、まだ決定できない箇所が存在する可能性がある。その位置、一般には区間は、Pから見れば順に使われ、Qから見れば逆順に使われる。Pから見て破綻しない限り')'を優先的に使うとよいかと考えたが、Q由来で中途半端な位置で決定している括弧をちゃんと考慮するのが難しい。そこで、開き括弧と閉じ括弧の個数の条件をP由来のものもQ由来のものも全部左から見た\pm 1累積和の条件に言い換えて、これが非負でなければならない区間P由来)と非正でなければならない区間Q由来)に分けてみた。ここまでするとどちらかの括弧を優先的に使うことができる。

最後に出来上がった文字列をチェック。ここまで書いてきたコードでもいたるところにチェックが入っている。3400Bにも膨れ上がったコードを提出するとREで、絶望。しかしREしか出ていないのはおかしいな……と思ってよく見ると、配列サイズが2N必要なところNしか用意していなかった。ここを修正してAC。1時間ちょっとかかってしまっている。

残り時間はDを考えて、手も足も出なかった。3完92位。

Cの解説は天才的。Sが正しい括弧列であるかその反転である場合は、確かに高々一通りに定まるらしい。では一般のSに対しても本当に正しいのか?今Sとそこから作られるP,Qがあったとして、新たに正しい括弧列TS+Tのように付け加えることを考える。このとき、Qにおいてはインデックス|S|+1\dots|S|+|T|を優先的に使うことになるので、Qの先頭に新たに|T|要素増えるような変化をすることがわかる。Pのほうは末尾に|T|要素増えて、いずれにしても連続部分列として現れるのでちゃんとそれぞれ復元できるということらしい。

また、僕がコンテスト中に考慮していた「2通りの文字列をマージしたときまだ決定できない箇所」は存在しないということもわかる。実際、その部分のコードをごっそり削除しても通ってしまって涙が止まらなかった。今日記を書きながら改めて考えてみると、Pで決定できない箇所に累積和が非負のフラグを立て、Qで決定できない箇所に累積和が非正のフラグを立てて、両方のフラグが立っている箇所があったら即座に-1を出力していたので、もし決定できない箇所があったら必ず-1を出力することになっていたらしい。この部分で実装にかなり苦しんだのに、まさかそうなっていたとは……。

昨日のSRMの結果が出ていた。全完2位で2699→2815(+116)。highest。

日付が変わったあたりから日記を書き始めて、校閲まで終わったのが午前8時だった。土曜日の後半と日曜日の部分しか書いていないのにこれだけ時間がかかっているのは異常。なろうを読んでみたりハーメルンを読んでみたりでかなり頻繁にキーボードを打つ手が止まっていたようだ。集中力がなさすぎる。

週記(2022/05/16-2022/05/22)

05/16(月)

先週は週記を投稿してからすぐ布団に入った。しかしそこからしばらくYouTubeを見てしまって、寝たのは正午だった。

午後4時前に起床。インターン先定例会までの短い時間で、多少なりとも進捗を出しておこうと思って調べ物をしていた。それでも進捗はゴミカス。今週は火曜日にミーティングがあるので、否が応でも何か進むだろう。

他の人の発表を聞きつつ、勉強会スライドの確認と手直しをしていた。文字に色を付けたり。定例会が長引き、普段より遅い時間から勉強会が始まった。使用したスライドは公開してある。

勉強会0516.pdf - Google ドライブ

テーマは関数型言語で、ラムダ計算の導入、そのSKIコンビネータによる表記、またそれを用いたHaskellにおけるポイントフリースタイルへの書き換えを話した。ただでさえ普段より遅く始まった勉強会で長い時間喋り散らかすのは躊躇われるため、スライドの式変形を大胆にカットして雰囲気で進めたつもり。しかし1時間ちょっとはかかっていたようだ。

発表に対して頂いたコメントで、結構置いてけぼりにしてしまったことを知った。当たり前で、ラムダ計算という目新しい表記を導入しているのに、それを使ってバリバリ計算するような内容を急いで喋っていては理解できるものも理解できない。勉強会でこういう「自分はよく知っているが他の人があまり知らない分野」について話すときは入念な戦略が必要である。例えば今回であれば、僕が最も伝えたかったのはポイントフリースタイルへの書き換えであったから、ここを重点的に……いや、それでもラムダ計算の導入は必要なのか。難しいな。

いくつかの部分ではラムダ式Pythonコードにしたものも添付していたので、その辺りは視覚的な面白さもあったのではないかと思っている。コンビネータSKをそれぞれPythonラムダ式で書いて、そこからIを作り、実際に適当なラムダ式を書きなおしてみる。すると見た目にはとんでもない文字列になるが、正しく動作する。この見た目に圧倒されてくれれば僕としてはもう満足。ただ理解の助けになったかというと微妙。Pythonラムダ式で書いたところで、そもそも「関数を返す関数」が理解しにくいので、わかりやすくはならない。

スライドを投稿してからゲーム理論の教科書を読み始めた。今日期限の課題が1個ある。集中を切らしてラノベを読んだりYouTubeを見たりしつつ、何とか期限の30分前に完成して提出できた。お互い7個の戦略を持つ戦略系ゲームの表を書かされる問題があって、手書きで書き始めたことを後悔していた。その後さらに2時間かけてもう一つ課題を倒した。

少しコードゴルフ。ARC140C。最短コードがdcでびっくりしたが、軽く読んだ感じ普通に場合分けしているように見えたので、もっと単純な方針をまともな言語で書いたら短くなると考え、やってみた。ただその単純な方針を考えるのに、他のコードがあまり参考にならずかなり苦労した。

1\dots Nを2つに分割して、適当にreverseした後交互に出力するというもの。前半後半に分割しただけでもほとんどの場合うまくいって、Nが偶数かつX=N/2の場合、またはX=N/2+1の場合のどちらかを特別扱いする必要がある。先に分割してしまうとうまくいかなかったため、分割する前に適宜reverseする方法を思いついた。整理していくと、後ろからN/2だけpopした後に残ったもののreversezipするだけで書けてしまい感動。reverseが2か所に出現するのがちょっと気になるが、Vimで書くと2度目の出現をほとんど省略できるのでむしろ短くなるのかも。ということで、そのVimで書いたものが最短になっている。

Submission #31753205 - AtCoder Regular Contest 140

午前4時頃にゴミを出した。この時間でももう外が薄明るくなっていて、夏(正確には夏至)が近づいてくるのを感じる。とはいえド早朝であることに違いはなく、誰もいないだろうと外に出たら、なぜかアパートの前の道路を原付がゆっくり走っていた。できるだけ見ないようにしてごみ集積所まで往復。大変怖い思いをした。

布団に入ってしばらくなろうを読み、午前7時就寝。

05/17(火)

30分おきに設定した目覚ましを何度か無視し、正午にやっとかっとで起床。昨日寝る前にしこたまなろうを読んだのが本当にバカ。まだ身を起こせるほどではなく、しばらくはまたなろうを読んでいた。

30分ほどコーディングした後、午後1時から1時間ミーティング。あれよあれよという間に、僕が書いていたコードが「本番環境に」デプロイされそうな感じになった。実は今までデプロイデプロイ言っていたのは全部ステージング環境の話だったのだ。そう変なコードを書いたつもりはないが、もし僕の作った処理が原因で落ちるなどしたら大変なことである。まあ、祈るしかできない。

そのあと作った処理のドキュメントを書いていた。書きあがって担当の人にお見せするとき、ついでにユースケースに合わせるような仕様の変更案を伝えると、実現すればかなり嬉しいという反応があったので、そこからしばらくはそのためのコーディングをしていた。デプロイ直前にこうやってコードに更新を入れるのは、当たり前ながら一般的に良くない。それに気づかずに更新しますという宣言をして、ひとしきり議論が発生した。この決着について話そうとすると、僕がやっていることをこれまでより詳細に説明する必要が出てくるため、割愛。午後5時くらいに一段落した。

コードゴルフをした。APG4bのEX11。以前までの最短はPerlで普通にevalするものだったが、AWKでコードを組み立てdcに食わせるコードで縮められていた。errorの場合分けもAWKのほうで行うとうまくいくらしい。これを単にVimに書き写してもどうしようもなかったので、もうちょっと本質的な改善を考えたい。実はerrorの場合分けはdcで行うほうが短くなるのではないか?[error]pqのような文字列をスタックに積んでおいて、ゼロ除算とそれ以外でスタックの様子に変化があるのを利用して検出し、実行する。Vimでうまいことコードを組み立てると何とか縮んでくれた。

その後、こちらもAWKで組み立てたほうが2B短くなることに気づく。しかしqでdcを抜けると終了コードが非ゼロになり、REとなってしまう。これを解消するため、+1Bでdcからシェルスクリプトを呼び出すテクを使うことになり、合わせて1Bの短縮となった。

Submission #31763359 - C++入門 AtCoder Programming Guide for beginners (APG4b)

コードゴルフをしていたら学食が閉まってしまった。しばらくなろうを読んでから食事し、いよいよおすすめのネット小説をまとめようと思って、とりあえず今年読んだものを週記からリストアップしていた。はてなブログの下書きの状態で塩漬けにしてある。多分、これ自体も昨年のように形式を整えて年末に投稿することになるだろう。昨年は1年分の週記をチェックするのが大変だったので、こうやって定期的に集めておくと便利そう。

今年読んだネット小説のまとめ - kotatsugameの日記

最新の週記まで確認し終えたところで気が抜け、しばらくなろうを読んでいた。するといつの間にか椅子の上で少し寝入ってしまったので、布団に移動。そこからもしばらくなろうを読み続けて、午前1時半ごろに寝落ちした。

05/18(水)

午前8時頃起床。手癖でYouTubeを開いたら犬山たまきさんが配信を行っていて、何気なく視聴してみたらしぐれういさんがいた。朝から声を聴けていい気持ちになれた。アーカイブはメンバー限定公開になってしまうようなので、一期一会。

しぐれういさんがこの配信の通話から抜けた段階で自分も視聴を止め、もう一度寝ようと考えた。しかしすっかり眠気がどこかに行ってしまったようで、適当にスマホを触っていたらうっかりハーメルンを1作読み始め、読み終えてしまった。「転生したら美少女VTuberになるんだ、という夢を見たんだけど?」。チートガン積みでかなり良かったが、配信風景の描かれ方と同接数やスパチャ額が見合っていないように感じられた。とんでもない数字を叩き出すのだから、本人の言動以外の部分だけでももうちょっと厳かというか、偉大さのある描かれ方をしていてほしかった。

syosetu.org

そのあと、昨日書いたデプロイについて少し確認とやり取りをして、午後1時に再度就寝。午後6時に起床。

先週日曜日に出たCodeChefの4問目の解説が公開されていたらしいので、読んだ。\gcd(a',P-1)=k以降嘘しか書いていないが、方針は分かった。頂いたリプライも参考に、B^k\equiv C^k\pmod P\Rightarrow \exists t\in\mathbb{Z}\;s.t.\;A^t\times B\equiv C\pmod Pの証明を自力で付けてみる。ここでkA^k\equiv 1\pmod Pを満たす最小の正整数、つまり乗法群における位数である。

PWMUL - Editorial - editorial - CodeChef Discuss

まず原始根gを取ってA\equiv g^aB\equiv g^bC\equiv g^cとおき、全体を指数の法M=P-1による合同式で書き換える。0\le t\lt kなる整数tに対してat+b-c\bmod Mの値を見て、0にできればOK。

ここで\bmod{M/k}を考えてみる。まずk=M/\gcd(M,a)よりM/k\mid aとなるから、at\equiv 0\pmod{M/k}。また仮定よりbk\equiv ck\pmod Mであるが、このとき両辺をkで割るとb\equiv c\pmod{M/\gcd(M,k)}が得られる。\gcd(M,k)=kなのでここでも\bmod{M/k}が出現して、まとめるとat+b-c\equiv 0\pmod{M/k}が言えた。つまりat+b-c、ひいてはat+b-c\bmod Mは常にM/kの倍数。

kの定義よりt=0\dots k-1at\bmod Mは一致しないので、at+b-c\bmod Mも一致しない。今[0,M)M/kの倍数はk種類しか存在しないため、そのすべてを1度ずつ取ると言える。当然その中には0も存在する。以上より、どこかのtat+b-c\equiv 0\pmod Mが満たされると分かった。証明終。

少しコードゴルフして、午後8時くらいに外出。もっと早く家を出たかったが思ったより二度寝で爆睡してしまった。ゲーセンに行く。05/02に帰省の途中で大宮のゲーセンに寄って以来なので、二週間以上間が空いたらしい。

今日は新曲を埋めた後14+を適当に触った。新曲から理論値+2、また14+のAJも+2。

ジェネリック緋蜂とは片手で連打しつつもう片手が同時押しだったり交互だったりする配置のことを指している。そこの噛み合い待ちで、ほかの場所、例えばジェネリックAttraqtiAはバッチリだった。

前にプレイしてからしばらく日を置いたらスッと出た。最高精度は以前日記でも触れた6-1-0なので、これでも倍以上の赤を出してしまっている。ただ14+で9950↑は初なので、嬉しい。記憶によれば1000コンボ時点で10個出ていたはず。最高精度を出したときはそこまで理論値だったので、前半の癖が残っていたのだろう。

久しぶりのプレイから2回で出た。こういうリザルトが特に苦労もせず出るようになったという点で自分の成長を感じる。昔は両手それぞれに認識難で片手トリルが降ってくる配置とか、ラストの高速四連打繰り返しに苦しめられていた。

閉店までいたあと油そばを食べて帰宅。実はゲーセンに入る前にも立ち食いそば屋で食事していて、それからあまり時間が空いていなかったので、食べきるのに結構苦労した。

帰宅するとatgolferに更新が複数流れてきていた。Perlに新手が出たらしい。shebangでオプション-aをつけて実行すると、入力が自動的にsplitされて@Fに保存される。splitだけだと自分で書いたほうが短いように見えるが、変数に入れるところまでやってくれるという点が二回以上使う場合に効いてくる。さらにオプション-pで出力を省略することで、実際に最短コードを更新するほど短くなったらしい。自分でもいろいろチェックして少し見つけたほか、それで縮んだものをさらに縮めようとしてしばらく考えていた。午前4時になって切り上げた。

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

TLでpaiza_runがpaiza_botとして復活したことを知った。出力が画像として返ってくるようになっている。昔僕がQuineを投げて無限ループさせたから……。当時のtogetterを見返しつつ自分の感覚を整理してみると、反省はしているけれど後悔はしていない、というくらいになった。当時の自分にカウントダウンQuineが組めるくらいの力があれば良かったのに。ところで、画像欄で遊んでいたのは普通にマナー違反だった。

なぜ無限ループに対応していなかったのかについては恐らくTwitterのリプライの仕様変更が効いている。もう僕も記憶があいまいだが、リプライ先IDがリプライの文面に含まれないようになったのがこの少し前だったはず。その前は勝手に文章の先頭にIDが書かれた状態になっていたので、Quineしようとしたとしても普通にinvalidなツイートが生成されるように見える。

togetter.com

明日のセミナーの準備を始めた。先週発表しなかった分があるとは言え、きちんと準備できていないし、1週間経って内容も頭から抜けてしまっている。特に、教科書を読んでいるときその場で考えて埋めた行間をちゃんとメモしていなかったので、その再現と、必要であれば改めてメモしておくことを行っていた。

全然終わっていないのだが、朝になってしまったのでいったん眠ることにする。午前5時半くらいに布団に入って、そこからなぜか30分YouTubeを見てから寝た。

www.youtube.com

05/19(木)

昼前に起きて、混む前に学食に行って、一旦帰ってセミナー準備をしようと思っていた。実際は正午になっても起きられず横たわっていた。

午後1時前にスマホに通知が来て、何かと思ったらもうすぐインターン先の会議が始まるとのこと。と言っても僕にとってはただ参加して聞いているだけでOKの、何というか大きな枠組みでの会議。そもそもインターン生が参加することを想定されているのかなど気になることはあるが、いいきっかけなので頑張って身を起こした。

会議を聞きつつ教科書を読み進めていた。全然終わらない。そもそもどれだけ飛ばしても今日1日で発表しきれる分量ではないな、と気づき、後半部分をすっぱり諦めることにした。

準備して午後2時半に出発。途中生協でラノベを受け取りつつ午後3時の直前に教室についてみると誰もいなかった。買ってきたパンを食べつつ先生にメールを送ってみるも、返事がない。

もう一人の同級生にLINEを送ってみると、その人が今日集中講義でセミナーに出られず、そのことを伝えられた先生も帰ってしまったということが判明した。ギリギリに来てしまった僕もちょっと反省すべき。とりあえず今日は帰宅することにして、来週は二人とも集中講義なので、次は再来週になる。

上のようなツイートをしたが、実際には読まず、院生室でしばらく駄弁っていた。入学から4年以上経った今でも僕が同級生の名前をほとんど覚えていないという話が出て(出したのは僕ではないことを念のため注意しておこう)、実際その時喋っていた2人のうち片方の人の名前がわからないということをカミングアウトした。ショックを受けたような反応をされてかなり申し訳なさがある。

その人とは昔から頻繁に生協で遭遇するしよく話すので、僕はもちろん友達だと思っていたし、反応から彼も僕のことを友達と思ってくれていたのだろう。当然顔を見れば一発で認識できる。ただ自分の中で、ある人が友達であることと、その人の名前を知らないことは矛盾なく両立してしまうのであった。名前を知らなくても適切に代名詞やジェスチャー・目線を使えば会話は問題なく行えるし、仲良くなってから改めて名前を確認するのは躊躇われる。今日ちゃんと名前を聞いたので、このような強烈なエピソードもあるから多分忘れない、と思う。

夕食を食べる約束をしていたホスフィンにセミナーが消えたことを連絡しておいたら、わざわざ院生室まで来てくれた。元からいた2人と別れてセミナーが行われるはずだった教室に戻り、2人でゼミっぽいことをした。お互いに今やっていることを喋るやつ。教科書はまだ読み始めたばかりなので、その前に読んだ論文について喋った。ホスフィンはもう具体的な問題に取り組んでいて、学士で卒論を書く必要がない数学科のぬるま湯加減が意識された。

午後6時くらいになって教室を出て学食に向かった。普段使う理薬食堂は今工事中で閉まっているので、少し歩いてけやきダイニングというところに行った。ここは窯で焼いたピザが売られている、ちょっとオシャレなところだった。ところで、3本の直線によって円は最大7個の領域に分割されるが、これを一般化すると怠け仕出し屋の数列というものになるらしい。

コンビニで原付の軽自動車税を支払いつつ帰宅。次の1か月の新刊ラノベをチェックした。買うことにしたものが19冊あり、2冊は予約受付が終了していたため、残り17冊を注文。予約受付の終了とはおそらく既定の冊数に達したからだと思うが、発売まで1週間以上あるのにもうそういう売り切れっぽい状態になっているのは驚き。人気シリーズの続刊なので理解できないことはないか。

今日のCF combinedはwriterが青だったのでサボって、深夜までラノベを読んでいた。FFの方が仙台に来ているようだったので、リプライを送って明日会う予定を立てた。

午後11時半からTCB47に出た。日曜日終了なのでここに各問題へのコメントを書く。

1問目はうっかりbit全探索を書こうとして、問題名が答えになっていることに気づいた。4問目はなかなか難しい。\min(X,A_i)\le 1の場合だけ加算する。\min(X,10^9)も一緒に管理して解いた。7問目は面倒。「楽しさがXより大である間常に行う」としたときT回以内に収まる最小のXを二分探索した後、残りの行動を全部楽しさXで行ったとして値を求める。ここで二分探索の範囲は必ずX\ge 0となるように決める。

8問目は難しかった。初手では適当に取る順番を決めて、swapしたときの合計時間の変化を見るものと考えたが、全然うまくいかない。しばらく考え込んで、取る順番より経路をもとに考えたほうが良いことに気づいた。ある経路を通るとき、各パンはそこを最後に通った瞬間に食べるのが良い。こうすると、まだ食べていないパンの区間を狭めていくようなdpが考えられる。区間のどちらの端にいるかも次元に持って、そこのパンを食べた後区間を一つ狭めつつどちらの端に移動するか決める。配列外参照で1WAと、時間も結構かかってしまい-29pt。

9問目は棒を取れるrの範囲をそれぞれ求めて区間スケジューリング。範囲の両端は2乗したものが有理数になるのでそれで持って、比較は__int128を使った。後からよくよく式をチェックしてみれば、確かに分子が10^{16}オーダーになり得るものの、比較で出現する有理数のペアはどちらかの分母が必ず1となっていたりして、うまいことオーバーフローしないようだ。直線と点の距離が線分と点の距離になる条件を記述し忘れ1WAで-15pt。

10問目はそれぞれの木で貪欲法を使い最大マッチングを求めた後、マッチングに使わない点同士を優先的に辺で結ぶのが良い。連結成分ごとに使わない点の個数を持って、残り1個同士をできるだけ結ばないようにする。

合計-44pt。WA2つがそれぞれしょうもない理由なのがつらい。8問目の配列外参照は、それだけでほとんどのケースに落ちるということが信じられず、他に原因があるものと思ってかなり念入りに確認していた。

少しコードゴルフしてから日記を書き、シャワーを浴びたりラノベを読み進めたりして午前4時半に布団に入った。そこからハーメルンの更新分を読んで午前5時就寝。

05/20(金)

午前11時起床。昨日、正午あたりには仙台駅近くにいると宣言したので、その通りにするため準備して出発した。

狙い通り到着。駅ナカドトールで食事がてら時間をつぶし、お相手の方から仙台駅に着いたとの連絡を貰ってすぐ駆け付けた。それほど自由に行動できない状況らしかったので、サッと会ってパッと帰る感じ。自己紹介して、アカウントのホーム画面を互いに撮影して、一人とツーショットを撮って、あとは少し喋って別れた。

そのままゲーセンに向かい、午後1時半から夕食を挟んで午後10時半まで遊んだ。

まず夕食前の成果。理論値が2譜面、14+のSSSとSSS+がそれぞれ1譜面、15のSSSが2譜面。15のSSSが2譜面!?

2回ある高速乱打がどうにもならず、追加されてすぐ出した鳥寸からちっとも伸ばせていなかった。今日は見えたまま手を動かしたらスルスル通って、2回目で鳥に。普段と何が違うのか全然わからないので、結局そうやって「押せる日」を待つしかないように思える。その分押せる人にとってはかなり簡単な部類の譜面だとされていて、実際これが14+初AJの人をTwitterで何人も観測した。

非対称トリルっぽいところ、具体的には85小節目で出したはず。ここは譜面が見えておらずいつも勘で押しているので仕方ない。今日はそれ以外の部分で全然出さず、我ながら上手かった。

今日解禁してすぐSSSまで出た。普通にやると追いつかないが、追いつかないくらい速いので擦っても通る。ありえないくらい簡単だった。これが15なら確かにContrapassoもotoriiも15。

特に運指は組まず全部見えたまま押して、癖がつく前に噛み合った。今日は信じられないくらい上手。スコアも今のところ15で最も高くなっている。

何度も上手上手と連呼しているように、今日はこれまでとは別次元に上手い日だった。もっと15のSSSを出せるかと思ってX7124と蜘蛛の糸も狙ってみたが、それぞれ7k弱、5kで断念した。癖がついてしまったので、やはり15と向き合うときはちゃんと運指を組まないといけないようだ。しかしそう考えるとPOTENTIALは上手かったな……。

ラーメンを食べて別のゲーセンでもう少しプレイした。食後すぐは眠かったのと、少しすると音ゲーサークルの人々が来て待ちが発生したため、適当に14+を触るくらいで終わった。とは言えこれも上手く、いくつか伸びたのと、larvaのAJを出した。本当にスッと出て、直後は手が震えていた。ただ精度は不甲斐ない。理論値を狙う時と同じ判定なのに、難しい譜面だとFASTに寄ってしまっている。赤Jでも通ればいいやとプレイするのではなくて、ちゃんと光らせることを意識してもいい頃合いなのかもしれない。そういう意識を持てるほど落ち着いてプレイできるようになったはず。

午後11時前に帰宅。疲れ果てて長い間ネットサーフィンをしていた。日付が変わったあたりでRebellionの理論値ツイートが流れてきて目を剥いた。

ニコニコ動画を見ながら日記を書いていた。午前6時くらいに切り上げ就寝。

05/21(土)

午後4時起床。二度寝はしないことにして起き上がった。用を足してすぐ生協の冷凍弁当の配達があって、少し早かったら応対し損ねるところだったと冷や汗をかいた。

YouTubeに時間を吸い取られつつ日記を書いて、午後9時からABC252に出た。

AtCoder Beginner Contest 252 - AtCoder

Aはdcで2B。BはRuby。ここからC++に切り替えた。Cは揃える文字を全探索して、どう止めるのが最適か考える。リールにおける文字の位置の被り具合を見ることで少なくとも何周する必要があるか求まるので、最後の周はどの位置まで回す必要があるかを確認すればよい。Dは手癖でjを固定しようとしてうまくいかなかったので、異なる3要素の取り方を求めて並べる方法を数えようとしたら、i\lt j\lt kとした場合とA_i\lt A_j\lt A_kとした場合が一対一対応することに気づいた。Eは初手がわからず少し悩んだ。初めのd_2,d_3,\dots,d_Nからどれくらい増えるか考えようとして、各頂点への最短経路をうまく選べば一切変えない状態が達成できると気づいた。

Fはかなり悩んだ。解説にあるような操作の二分木への言いかえを真っ先に行ってしまって、そこから各要素に深さを割り当てる方法をずっと考えていた。なんとなく見覚えがあるのに全然解けないな……と思いつつソートしてdpなど考えているうちに、急に脈絡なく最小要素2つのマージを繰り返す方法を思いついた。正当性もわからないが、自分の直感や既視感はこれが正しいと強烈に主張しているので、実装。しかしWA。実はそれ以前の考察で\sum A\lt Lの場合は最初に使わないパンを切り離してよいという大嘘をついていた。幸い「使わないパンはまとめて切り離す」というところまでは考えていた証明も正しそうなので、A_{N+1}=L-\sum Aと追加して同様のことを行ってみたら通った。

Gは簡単。区間[l,r)が頂点lを根とする木になる場合の数を、区間dpで求めてみる。特に工夫しないと区間ごとにO(N^2)のdpで計算する方法が考えられて、とりあえずサンプルは合う。ここで区間ごとのdpをよく見ると、左端を固定したとき右端を伸ばすごとにO(N)で更新するように書けていることがわかる。区間dpで扱う区間の順番をl降順・r昇順に書き直して、rを動かすときにdp配列を使いまわすようにしてO(N^3)になった。

Exは、後から振り返ってみれば惜しいところまで行ったようだ。まず、ネックレスの作り方がそれほど多くないことに気づく。適当にdpして調べてみると、N=70で最大10^{11}くらいにしかならないらしい。よって半分全列挙ができる。列挙したものをA,Bとして、BをBinaryTrieに持っておく。美しさがX未満になるようなネックレスの作り方の総数を求めるときは各a\in Aに対し\#\{b\in B\mid a\oplus b\lt X\}を求めればよく、これはBinaryTrieでO(\log\max B)になる。Xを二分探索することで\logが2つついた解法が得られた。案の定TLEして、BinaryTrieの構築だったり探索をベタ書きして高速化を試みたが、結局通らなかった。

7完で58位。Fが遅いのは反省。二分木へ言いかえる前に操作を逆順に見ることができていれば、これがマージテクと全く同じであることに気づけただろう。少なくとも、このことを知ってからはそうとしか見られない。既視感もこの事実からきているはずだ。

コンテスト後にExを改めて考えてみた。コンテスト終了直前は、すべてのa\in Aに対して毎回BinaryTrieを根から辿るのではなく、ある程度まとめつつ辿ろうとしていた。つまり、そのノードに到達するAの集合を管理するということ。そうやってX未満になることが確定した個数をカウントする実装をよくよく見ると、Xのbitが立っているときだけカウントが増えていることに気づいた。このことから、BinaryTrieを辿りつつXの上位bitから立てるか立てないか選ぶことで、カウントした値を二分探索のしきい値ギリギリにできることがわかる。BinaryTrieの\logと二分探索の\logをまとめられて、無事AC。

コードゴルフ。Aは提出スピードで辛くも勝利を掴んだ。13秒。画面の録画を確認したところ問題一覧ページへの遷移に5秒かかっているので、A問題のURLを用意しておけば夢の1桁秒ACが達成できたのかもしれない。B、CはRaku。DでもRakuのBagを使ってみて、TLEしなかったもののRubytallyのほうが短くなった。FはPythonのheapqで、負け。A=sorted(A)みたいなことを書いていたのは反省。これはA.sort()である。他は手付かず。

午前1時からTCO22 R2A。Stage3でR4への進出が確定しているはず……であるが、CLISTはあくまで非公式であるから、絶対確実とまでは信頼しきれない。公式からの発表はまだないため、そこそこまともな問題が出るとの評判も聞いたことだし、念のためR2にも参加しておくことにした。

TCO22 Stage3の結果が今日のSRM826で確定していた。僕はSRM825に参加していないのでちょっとひやひやしていたが、それ以外の成績がまあまあ良かったので問題なくRound4への進出が叶った。TCOの予選はcombinedのratedなので、毎年通行料などと言われて評判は良くない。Topcoderのシステムでcombinedにするのはさすがに時代遅れ。ナウなヤングはFull-Feedbackにしか出ない。 https://clist.by/standings/tco22-algorithm-stage-3-28608402/

週記(2022/03/28-2022/04/03) - kotatsugameの日記

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

参加者を見て赤が多いなと思っていたが、combinedだけあって部屋分けで分散し、Roomには僕含め3人しかいなかった。

Easyはタコ足配線の問題だと気付いて問題文をスラスラ読めた。分岐できるものをとりあえず並べて、空いたところに残りの家電を差していく。どこがどれだけ空いているかを適当なコンテナで管理して、使うたびにpopしていくような実装をした。

Medはカス。これをTopCoderのシステムで出題するのは人の心がない。いろいろ方針はあると思うが、自分の解法を説明する。まずleading zeroを作ることによって桁数を減らして、Yの桁数未満にする。できなければYは一桁なので、X=1としておく。次に9を並べた形を作ってインクリメントすることで桁数を増やし、Yの桁数と一致させる。特に、一致した時の形が10のべき乗であるようにする。先ほどX=1としたのはこれを満たすためである。あとは最下位桁を弄ってswapを繰り返すことで、基本的には目的の値が得られる。

ただし、Yの最上位桁以外がすべて0の場合は注意する必要がある。最上位桁を揃えた後swapすると、最下位桁に1が来てX=Y+1となってしまう。これはどうしようもないので、代わりにY-1を作ってインクリメントすることにする。Y10のべき乗の場合は桁数が減ってしまうが、その時は元からX=Yとなっている。あとは念のためYが一桁の場合も別に処理しておいた。

Hardは半分全列挙やるだけ。なぜ900点がつけられているのだろうか。3問提出して25位あたりで、残り時間はMedを1\le X,Y\le 1000で走らせてチェックしていた。WAが大量に表示されて心臓が消し飛びそうになったが、チェッカーの間違いだったことに気づいて一命をとりとめた。

今回はChallengeフェーズも頑張る必要がありそう。しかしMedは読みたくないので、Easyだけ集中的に読んでいた。その甲斐あって、本当に久しぶりに一つ落とすことができた。一つしか口がない分岐について、それを別の分岐と繋ぐために使ってしまったのに、さらに家電を差そうとするコードがあった。そういうものをスキップするときにwhileではなくifを使っていた、というミス。

システスは全部通って、12位まで上がった。レートは2655→2699(+44)。部屋のEasyがもう一つシステス落ちしていて、何かと思って読み直したところ配列外参照らしかった。たとえ気づいていたとしてもこれにChallengeする勇気はない。

日付が変わる前あたりにあったしぐれういさんの配信アーカイブを見た。待機画面のイラストに描かれたロリういの表情がかなり良い。その後、朝まで日記を書いていた。午前7時に布団に入り、そこからなろうを読んで午前9時半就寝。

www.youtube.com

05/22(日)

今日がAHC開始の日だと思っていて、正午にかけておいた目覚ましで起床。慌ててコンテストページを開き、一週間後であったことに気づいた。即座に二度寝

午後4時半起床。今日は通常のOpenCupがなく、代わりにadminから配られたコンテストにバーチャル参加することになっていた。チームメイトの一人が通常の開始時刻である午後5時に間に合わないらしかったが、バーチャル参加なので開始時間には融通が利く。3人揃ってから開始することにして、チームメイトを待つ間はラノベを読んでいた。

午後6時半からスタート。今日のコンテストタイトルにはPTZW 2022 Day 3(Kazakhstan Contest)と書いてあった。

チームで6完。自分が担当した問題は……ない!なんと5時間で1問も解けなかった。ひっじょ~~~に苦しい。途中から思考がフワフワしてしまい、取り組む問題をコロコロ変えていたのだが、これを1問に絞ったところでどうしようもなかっただろうと断言できるほど手も足も出なかった。このコンテストにはいっそ感動した。わざわざadminが選んで配布したコンテストだけあって、どれも問題文がシンプルで、その上ハチャメチャに難しいわけだ。自分の伸びしろを感じる。しかしこの伸びしろを、僕はおそらく埋められないままICPCを引退するのだろう。

直後、午後11時半からCF #793 div.2。

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

Aから少し難しい。s{\rm rev}(s)を並べ、一文字削除して一致するという条件を線を引くなりして確認してみると、ある範囲の文字がすべて一致している必要があるとわかる。最近ARCで見たことがある気がする。とにかく、sの中心から同じ文字が連続する範囲を求めればよい。|s|の偶奇には気を使う必要があった。

A - Remove One Character

Bはi\ne p_iなるp_i全体のbitwise ANDが答えになる。これでソートできるのは、その値を動かすことで一つ一つ揃えていけることから明らか。逆に、p_iを動かそうとするときはXを含んでいる必要があるので、Xは動かす必要のあるp_i全体のbitwise ANDに含まれることになる。

Cは同じ値ごとにまとめて、{\rm LIS}(a){\rm LIS}(a')のどちらに含めるか決めていく。同じ値の要素が二つ以上あるなら両方に一つずつ含めることができて、一つしかないなら現状短いほうに含める。一つしかない値が一種類以上あった場合、そのうち一種類を両方に含めることができるので、これを最後に処理する。これまでと同様短いほうを一つ伸ばすとしてよい。

Dはsに含まれる'1'の個数が奇数またはゼロのとき以外必ず構築可能。隣接している頂点をマージしていくことで交差が発生しない。'1'は必ず一個以上存在するので、'0''1'が並んでいるところをマージし、新たに'1'であるような頂点と見なす。これを繰り返すと残り全部'1'になって、このとき頂点数が偶数個になっているため、適当な頂点を中心にしてウニグラフを作ればよい。

Eはかなり面倒だった。swap操作を辺と見ると森になっているので、木ごとに解く。葉から順番に揃えてよいという大嘘をついた。p=\{2,4,1,3\}(1,2),(2,3),(3,4)が反例。

一度辺(swap)を使うとそこで木が分割され、以降二つの木の間で要素を移動できないので、使える辺を見つけるために適当に根を取って各部分木について足りない要素・余っている要素の集合を管理することにした。これは集合のXORで書け、下から順にマージテクで求められる。u\rightarrow vという親から子への辺について、vの部分木に対する集合が\{p_u,p_v\}であればよい。そのように使用可能な辺を見つけたら即座に使い、v以下については別の関数で対応する。「使用可能な辺を即座に使った」という条件から、v以下の部分木で次に使える辺があるとしたらそれはp_vが書き換わったばかりのvに接続していなければならない、ということを利用して、下りながらどんどん使っていく。

使える辺を探すときはuから出ている辺を全部チェックすればよいと考えていたが、それではp_uが書き換わり新しく使える辺が出現する場合に対応できないことに気づいた。何とかしてチェックを高速化する必要がある。ここで、求めた集合のサイズが常に0または2であることに気づいた。このことはvalidな順番に並べたswapで後ろから帰納法することで確認できる。そして、再度「即座に使う」条件を用いて、vの部分木に対する集合はサイズ2かつ一方が必ずp_vであることも言える。なぜなら、v以下の辺が使われるのはu\rightarrow vの辺が使われた後であり、p_vは必ず辺u\rightarrow vu側に行かなければならないからだ。

よって、「p_vでないほう」をキーにして辺を保存しておくことで、使える辺=キーがp_uである辺を即座に取得することができるようになった。今、集合のサイズが高々2であることから、各部分木に対する集合を直接保存しておけるため、u\rightarrow vを使った後v以下を揃えるときは、それを参照しつつ木を下っていける。提出したら何とか通った。

Fは見た目こそヤバいものの簡単。コストの条件からより近い頂点に向かって流すと嬉しいとわかる。コストを分割して考えると、l\le i\lt rについてa_ia_{i+1}の間を通るフローの流量は\left|\sum_{k=l}^i b_k\right|であると言える。よってS_j=b_1+\dots+b_jとして、(a_{i+1}-a_i)\times|S_i-S_{l-1}|l\le i\lt rに渡る和を求められれば良い。S_i\gt S_{l-1}の場合とS_i\lt S_{l-1}の場合に分け、Sの降順・昇順に見て、a_{i+1}-a_i(a_{i+1}-a_i)\times S_iそれぞれの和を管理するセグメント木を用意しておけばよい。実装が間に合わなかったが、システス後に書き上げて提出したら通った。

システスは全部通って5完28位。Eの正当性は日記を書きながらassert等で必死に確認したものであって、コンテスト中は正直半信半疑だった。

TCB47が終了していた。3位。2位とは1pt差で惜しいところ。1位はこのセットでも満点近くを叩き出している。自分もしょうもないWAがなければなあ、とそれなりに悔しさを感じた。

日付が変わったあたりで先生からメールが来ていたのに気づいた。来週火曜日から金曜日は集中講義であるが、それに関連する座談会なるものが月曜日に予定されていて、対面で出席してくださいとのこと。直前に言われるとかなりびっくりしてしまう。インターン先定例会と被ってしまうためオンラインで勘弁してほしい気持ちが強いものの、こういうところでは学業を優先するのが正解なのだろうとわかっている。定例会を休むと伝えておかなければならない。

朝までかけて日記を書いていた。今週もかなり溜めていて、木曜日以降を一息に書き上げた。土日はコンテストが少なく時間に余裕がありそうだなと思っていたのに、実際は何もできていない。月曜日締め切りの課題が2つあることに今更気づいたりもしてしまった。謎の忙しさをずっと感じている。おすすめのなろうを纏められていないし、いくつかまた溜まっている質問への回答もできていない。しばし待たれよ。