読書記録(2023)

kotatsugame.hatenablog.com

1月

  • 1日
    11文字の檻
  • 2日
    あたしは星間国家の英雄騎士!1
  • 4日
    現代社会で乙女ゲームの悪役令嬢をするのはちょっと大変4
  • 6日
    紅蓮戦記2
    ブラックな騎士団の奴隷がホワイトな冒険者ギルドに引き抜かれてSランクになりました8
  • 13日
    クラスで2番目に可愛い女の子と友だちになった3
  • 14日
    黄金の経験値
  • 15日
    ガリ勉くんと裏アカさん1
    迷子になっていた幼女を助けたら、お隣に住む美少女留学生が家に遊びに来るようになった件について2
  • 18日
    迷子になっていた幼女を助けたら、お隣に住む美少女留学生が家に遊びに来るようになった件について3
  • 20日
    完璧な俺の青春ラブコメ

2月

  • 12日
    隣の席の美少女をナンパから助けたら、なぜかクラス委員を一緒にやることになった件
  • 17日
    才女のお世話4
  • 18日
    才女のお世話5
  • 22日
    ネトゲの嫁が人気アイドルだった3
    ひきこもりの俺がかわいいギルドマスターに世話を焼かれまくったって別にいいだろう?3
  • 23日
    転生したら皇帝でした1
  • 24日
    転生したら皇帝でした2
  • 27日
    Vのガワの裏ガワ2

3月

  • 2日
    世界で一番『可愛い』雨宮さん、二番目は俺。
    異能学園の最強は平穏に潜む

週記(2023/03/13-2023/03/19)

工事中。金曜日以降一部の記述は参加記のほうに切り出される可能性があります。

03/13(月)

午後1時半起床。1時間くらいスマホを触ってからようやく布団から脱出した。

準備して今日も5h。Muscatキャンプの今日のセットは将来的にUniversal Cupでも使われるらしいので、日本チームで示し合わせて別のセットを走ることにした。中国ICPCの2021 Finalらしい。

それにしても、キャンプに参加するからと言ってインターンの定例会をお休みさせてもらったのに実際に走っているのはただのバチャとなると、少し罪悪感がある。

Dashboard - The 7th China Collegiate Programming Contest, Finals (CCPC Finals 2021) - Codeforces

書く

感想戦を終えてからはずっと先週の週記を書いていた。CF一つと5h二つが書き終わらないまま体裁だけ整え、日付が変わる直前に投稿。その後朝までかけてCFと5h一つについては書き足した。

午前6時くらいに布団に入ってからはなろうを読んでいた。三章まで読み進めたが主人公の言動があまり好きになれず放棄することに決めた。一応ここに記録しておく。

https://ncode.syosetu.com/n6938fe/

午前8時半就寝。

03/14(火)

午後2時半起床。今日のMuscatキャンプのセットも昨日と同じ理由で回避し、中国ICPCのMianyangセットを走った。

Dashboard - 2022 China Collegiate Programming Contest (CCPC) Mianyang Onsite - Codeforces

書く

感想戦の後は今日のコンテストのupsolveをしていた。しかしDが全然通らない。そのうち椅子の上で寝てしまい、少し目を覚ましたタイミングで慌てて布団に移動しもう一度寝た。日付が変わったくらいだった。

午前4時前に起床。1時間くらいかけてようやくDを通した。double型の数ABを等号付きで比較する際A<B+epsとしていたのをA<=B+epsとしたら通った。Bの値が大きすぎる場合にepsを足しても値が変わらず、等号なしの比較になってしまっていたらしい。

朝まで先週の週記を書き足していた。何とか残っていた最後の5hについても書ききり、ようやく完成。完成といっても校正は行っていない。その合間になろうで「熾天使さんは傍観者」を読了した。

https://ncode.syosetu.com/n8651ia/

面白かった。設定が好みなのはもちろん、話のテンポもよくてストーリーがスイスイ進行していく。その中でも必要なイベントや見せ場はしっかりこなしていて満足。

午前9時頃布団に入り別のなろうを読んでいた。正午ちょっと前にようやく就寝。

03/15(水)

午後2時半起床で激烈に眠い。食事していざMuscatキャンプ最終日。

今日はe-judgeというジャッジシステムを使用するらしい。コンテスト直前になってサイトへのURLが共有されたが、最初に伝えられたものが間違っていたらしくログインできずに焦っていた。問題を報告するためTelegramのアプリをインストールしたところで正しいものが再度共有されているのに気付いた。

少し遅れてコンテストを開始すると、なぜか開始より前に5問解いている状態となっていた。ペナルティの値が負になっていて面白い。運営に連絡してしばらくしたら直っていた。

笑っていられたのはここまで。言及禁止なので詳しく書けないが凄まじいコンテストだった。自分たちは5時間で1完。これでも参加チームの中では解けているほうである。

コンテスト中に解法が出た問題を通し切るため午後11時頃まで粘着し、なんとかACをもぎ取った。その後解説を読んだがあまり理解できず苦しかった。

解説pdfは実はWhatsAppというSNSのキャンプ公式チャットにしか上がっていない。SNSへのログインのために電話番号が要求されるため入っていない人もいるので、今更だがダウンロードして日本チームに配った。

日本のUniversal Cup参加者が集まるDiscordサーバにプライベートチャンネルを作ってそこにアップロードしたら、実はそのサーバでは全員管理者になっていて実質誰でも見える状態になってしまった。必要な人に行き渡ったのを確認してすぐ消した。まあUCで使う予定のないセットだけ走ったので大丈夫だろう。

日記を書いて午前6時就寝。

03/16(木)

午後4時過ぎ起床。インターンの進捗としてなんとかドキュメントの体裁を整え、午後5時から1on1に臨んだ。

進捗報告として書き足したところを説明しつつ、曖昧な点について確認しつつ修正。もっと丁寧に書いたほうが良さそうなところが残っているもののひとまず完成という感じにはなった。ちょうどこのドキュメントを使う予定の方が明日から稼働されるようなので、ギリギリだった。

来週のタスクを設定したあと、ちょっと前に書いたAPIを叩くプログラムを実用する機会があったが、このタイミングで少し機能を追加したり対処が漏れていたケースで落ちるのを修正したりの作業が発生した。結果1on1終了は少し伸び、午後7時半になった。

疲れ果ててハーメルンを1作読了。「貴方はウマれ変わったのでトレセン学園で無双を希望しています。」。5話完結のほぼ短編だった。

syosetu.org

「貴方は中央トレセン学園から追放されることを希望しています。」作者の別作品。面白そうだと気軽に読んだがラストがちょっと曇り気味で、身構えていなかったためそこそこ衝撃を受けた。面白かったことには変わらない。5話ではしっかり他人から見た主人公も描写されており健康に良い。

食事して午後9時頃からTCB56を解き始めた。今回は大変だった。

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

1問目、2問目はよい。3問目は格子点を全探索すればよいことに気付くのに一瞬かかった。4問目は4方向を見るループを要求されて面倒。

5問目。文字ごとにそれが書かれたマスを数え降順に並べることでSが復元できる。文字の置換は常に直前に置換されたマスの一部だけが対象になっているので、ある文字で一度置換されたマスを集めるためには、その文字より後ろに並んだ文字が書かれたマスを全部集めてくればよい。そうして集めたマスから座標の平均を求めることで、置換の際にどのマスが(x,y)だったかわかる。そこから方向を特定して出力する。

このアルゴリズム自体はすぐ思い付けたのに、焦ってひたすらバグらせ盛大に時間をかけた。詰めずに書き始めたらソート順や出力順を間違えているし、座標の平均を取る対象が間違っているし、typoもいくつかあるし大変だった。17分かけたため-8pt。

6問目はマス(X,Y)を白にする場合と黒にする場合を両方試す。白にする場合はそこを避けるように貪欲に置いて置ききれるかチェックする。黒にする場合はとりあえず貪欲に置いてみて、どれだけずらせるかも加味し目的のマスを黒にできるか判定する。実際には1マス以上ずらせれば必ず可能だったが気づいていなかった。変数の初期化ミスで1WA、時間も16分半かかっており-13pt。

7問目は答えとなるKを二分探索する。隕石から避難するためのマスとして考える必要があるのは私有地の「端」のみであり、具体的には(a,b)から上下左右にKマス離れたマス、あるいはそのようなマスが存在しなければグリッドの端に行ってさらに別の方向に可能な限り向かったマスである。つまり候補が高々8マスしかないため受けるダメージの計算が十分高速に行える。

8問目はマス(i,j)の情報をデータ構造のインデックスi+jに置き、適切に係数を掛けながらの取得を頑張る。左上マスが(1,1)の長方形領域に対して総和を取得できれば十分。係数は1,2,3,\dotsとなる区間、定数の区間\dots,3,2,1となる区間に分かれるので、それぞれデータ構造を用意して対応した。

9問目は難しかった。M\le 100のケースから解いた。Aにしか存在しない要素、Bにしか存在しない要素、ABの両方に存在する要素の数をそれぞれ固定するとf(A,B)が計算できる。どの要素を選ぶかは単にcombinationで、ABの数え上げはあらかじめ包除原理でやっておけばよい。O(M^3)

この考察を元にK\le 10のケースを解いた。こちらは積の和典型で、f(A,B)に寄与する2要素をK回重複あり・順番込みで選び、その要素たちを選べるようなABを数え上げるのを目標にする。これまで選んだことのある要素を上の3種類に分類し、それぞれカウントしながらdpすることができる。ここまでの計算量はO(K^4)で、ただし遷移の定数倍がかなり重い。

その後ABを数え上げる。使える要素が大量にあるうちO(K)個の要素を必ず含む必要があるという条件になるが、これもその「必ず含む要素」について包除を行うことで計算できる。41分かかって-20pt。

10問目は……苦行。ただし実装はそこそこ上手かったと思う。1列ずつ右に追加してチョコを作ることにし、これを状態間の遷移だと捉え行列累乗で高速化する。つまりやるべきことは状態の列挙と遷移の列挙である。

直前に追加した列のうちどのマスとどのマスが連結か、どのマスが空きマスか、どの空きマスがチョコの外に繋がっているか、また穴を作り終わったか・チョコを切り出し終わったかが分かれば遷移できる。最後の要素については適当に0、1、2で表しておく。それ以外の要素については列の各マスに番号を振っておくことにした。

空きマスもそうでないマスも連結成分として高々3種類を区別できればいいから、それぞれ0、1、2と3、4、5を割り振ることにする。同じ数字なら同じ連結成分に属していることになる。また特にチョコの外に繋がっている空きマスには番号0を割り当てることにした。

以上でh+1個の整数が状態になる。列挙の際は、何もない状態だけからスタートして、一つ右に追加する列2^h通りを全探索し新しい状態が見つかったらまた同様に計算するということを繰り返した。こうすると遷移についても同時に求まるため都合が良い。

最後に残ったのが、ある状態に1列追加して次の状態を求める関数の実装について。ここはUFを使い新しい列の各マスと連結成分に対する番号をマージするとまあまあ簡単だった。UFの連結成分をそれぞれ見て、追加した列のマスを含むなら番号を適切に割り当て、そうでないなら穴やチョコを作り終わったと判断してその情報を適切に更新、あるいは条件を満たさないと判定する。

h=6でも380状態になり、行列累乗は十分間に合いそう。しかしTLEだった。行列を生配列に持ち、さらに行列累乗してから最初の状態を掛けるのではなく同時に行う(つまりA^3\vec{b}(A^2\times A)\times\vec{b}ではなくA^2\times(A\times\vec{b})と計算する)ことにしたら通った。69分1ペナで-58pt。

3時間弱かかり日付が変わるくらいの時間になってしまった。ここから明日のセミナーの準備を開始し4時間ほどかけて終わらせた。クラトフスキの定理の強さに感動。グラフのある性質がその部分グラフに遺伝するなら、K_5K_{3,3}の細分という具体的な例についてのみ確かめることで、平面グラフでないもの一般がその性質を持つと証明できてしまう。

シャワーを浴びて布団に入ったあと、なぜかしばらくTLを眺めるのが止められなかった。午前5時半就寝。

03/17(金)

起きたら午前9時45分だった。ただでさえ遅刻しそうなのに布団で少しダラダラしていたため、午前10時を回ってから家を出ることになってしまった。

午前中は同級生のセミナー。今日はなんだかずっと詰まっていて補題一つの証明も終わらなかった。自分でも教科書を読んでみたがどこに困難があるのかいまいちわからない。詰まっている部分の周辺について自分の理解を説明しても納得行かなそうだったので、自分がなにか陥穽に気づいていないだけかもしれない。

昼食を摂りつつ正午からはオンラインで海外の方のセミナーを聞いた。博士課程の方の関係者らしい。自分たちがどのくらいのレベルにあるのかわからないようでかなり丁寧に説明していただけたが、今日扱っていたのが\mathbb{Z}/n\mathbb{Z}だったため十分理解できたものと思う。

環、特に\mathbb{Z}/n\mathbb{Z}からグラフを作るという話だった。n素数だと完全グラフになってしまうし、そうでなくてもかなり密に辺があって、それほど面白そうに見えない。また今のところ作ったグラフを調べて得られるような環の性質もないらしく、何がしたかったのか伝わらなかったという感想。

午後2時前からは自分の発表。そこそこ駆け足で説明したら1時間半ほどで終わった。発表について特に反省すべき点もないと考えている。

午後4時頃帰宅し、1時間半ほどかけて荷物をまとめオンサイトに向けて出発した。午後6時過ぎ発車の新幹線に乗ることにしたが東京まで2時間半ほどかかるらしく、着いてから夕食を摂る時間がなさそうだったので駅弁を食べた。

新幹線の車内では日記を書いていた。ただし最後の20分ほどは寝ていたはず。今日はかなり混み合っていて、自由席車両では立ち乗りしている人も見られた。

東京駅に到着。乗り換えに手間取りつつ渋谷駅から池尻大橋駅と辿って、少し歩いたところが今日の宿だった。伝えていた時間から30分ほど遅れてしまったが無事チェックインできた。

部屋に入ったのが午後9時40分頃。即座にPCを開いてyukicoder 381に出た。

yukicoder contest 381 - yukicoder

電車に乗っている間にコンテストが開始してしまったので後ろの問題から読んでいた。その流れで今日は逆順に解いた。

Fは結構面白い。まず良い印の付け方に関する性質を考える。1行目は自由に付けて良い。2行目からは1マス決めると残りは一意になるが、具体的にどういう配置になるか調べてみると、なんと1行目と全く同じか完全に逆のどちらかになっていた。

つまり良い印の付け方は次のように定式化できる:0または1からなる数列R_1=0,R_2,\dots,R_HC_1,\dots,C_Wに対し、「マス(i,j)に印が付いている\Leftrightarrow R_i\ne C_j」とした良い印の付け方が一対一対応する。

マスを、タイブレークを適当に決めて整数の降順に並べる。自分より前に並んだマスに印が付けられず、かつ自分に印が付けられるようなRCの選び方を数えると良い。RCの同じ値になるべき要素をUFでマージしていくことで、その連結成分数として自由度が求まる。R_1=0と決まっていることに注意。

E。最初の順列で転倒数に寄与しないペアは操作後も寄与しない。そうでないものについてそれぞれ操作後も寄与するような分割方法を数えれば転倒数の総和が求まる。

自分は寄与しないものを数えて全体から引いた。1\le i\lt j\le N(ただしP_i\gt P_j)について、ijの間に仕切りがなければ一緒にソートされて寄与しなくなる。そのような場合の数は2^{(i-1)+(N-j)}で、適当にバラしてBITで記録すればjに対してiを一括で計算できる。

Dは頂点1を経由することで距離2での移動が必ず可能なので、距離1で移動できるペアを数える問題になる。つまり\sum_{i=2}^N\varphi(i)を求めればよい。ここでi=1を取り除いているのは、\gcd(1,1)=1だからといってペア(1,1)を数えてはいけないからである。

あらかじめ107まで求めることができる。\varphi(n)=n\prod_{p\mid n}(1-1/p)なので、最初a_n=nとした列を用意し、素数pを列挙しつつp\mid nなるn全てに対しa_n\leftarrow a_n\times(1-1/p)と更新すればよい。最後に累積和を取る。計算量はエラトステネスの篩と同じ。

Cは最初すべての要素を\min(A,B)にした後一番小さい要素から順に(A+B)/2\max(A,B)と引き上げていき、毎回答えを更新する。最小値を固定しているとも思える。

BはとりあえずKの条件だけ満たし、後から余った0を先頭に近いところに、1を末尾に近いところに入れる。Kの条件を満たすには、先頭の文字を0と1両方試した上でK回直前の文字と異なる文字を置くとよい。この過程で足りなくなったらアウト。K=0の場合に余った0や1を入れる場所がなくてもアウト。

A。うしっぽい数の大小関係が(c,a,b)の辞書順で決まっている。(a,b)が36通りあるのでc=\lfloor(N-1)/36\rfloorとわかり、(a,b)を適当に求めた上で実際に整数を作ればよい。作ると言っても直接出力するだけだが。

コンテスト開始から1時間弱で全完、スコアは低めで16位。

シャワーを浴びて日記を書き、日付が変わってすぐ就寝した。

03/18(土)

午前5時前にうっかり目を覚ましてしまい、しばらく眠れず1時間ほど輾転反側していた。

午前7時15分に目覚ましで起床。同じホテルに止まっているへのkと一緒に朝食を摂った。一人2個までのパンとフリードリンクということで少し物足りない。時間帯の問題か全然人がいなかった。

午前8時半頃出発し歩いて会場に向かった。開場を少し待ち、ほぼ一番乗りで入場。席に荷物を置いた後開会式までずっと懇親していた。

午前10時、開会式。10分弱話を聞いた後ヌルっとコンテストが開始した。

Toyota Programming Contest 2023 Spring Final - AtCoder

Aを開いたが解けない。ここで無理に粘着すると後々響くことが分かっていたので、同じ300点が付けられていたこともありBに進んだ。

Bはクイズiの直後にクイズjに回答するときとその逆でそれぞれ期待値の式を立て、比較してどちらを先に行うのがよいか調べるのが典型テク。

03/19(日)

週記(2023/03/06-2023/03/12)

03/06(月)

午前0時前に目を覚ましたが、布団でハーメルンを読んでいたら2時間くらいでまた眠りにつけた。もし眠れなかったら生活リズムが大変なことになっていたから、危ないところだった。

午前9時起床。夕方までずっと先週の週記を書いていた。日曜日を生活リズムの狭間に消し去ったから残っているのは土曜日の分だけだったのに全く捗らず大変だった。たっぷり寝たうえで朝起きるという経験がほぼないため脳が何か勘違いをしているのか、睡眠時間は足りているはずなのに微妙な眠気が取れない。シャワーを浴びてもそれほど効果はなかった。

午後4時半からインターン先定例会。先週もコードをちょっと書き足しただけ。今週はドキュメントの清書を進める予定。このタスクは先週の広義月曜日の1on1で振られたものだからもう一週間くらい経っているが、まだ手を付けられていない。

勉強会は構築問題について。背景の専門的な話を省くと次のようなものだった:1\dots nの中で「ペアのペア」( (a,b),(c,d))を考える。ここでa=bまたはc=dかもしれないが、\{a,b\}\cap\{c,d\}=\emptysetである。1回のクエリでdisjointな「ペア」の集合を一つ指定し、そこから二つ取り出して作れる「ペアのペア」を全て取得できる。できるだけ少ないクエリでありうる全ての「ペアのペア」を取得せよ。

有限射影平面を用いた非常に綺麗なO(n^2)解が紹介された。n-1素数だとして、位数n-1の有限射影平面を考え、そこにどの3点も一直線上にないようにn個の点を取り1\dots nと対応付ける。「ペア」を、たとえそれが同じ要素二つの組であっても、2点を結ぶ平面上の直線と思う。そして「ペアのペア」を直線の交点と見なす。

このような直線の存在や交点の存在、また唯一性は有限射影平面の特徴から導かれる。さらに「ペアのペア」となった交点がn個の点のどれとも一致しないことがその取り方からわかる。

よって逆に、取らなかった点それぞれに対し、そこを通る直線に対応する「ペア」を全部一度に聞けばよい。こうして聞く「ペア」がdisjointであることも点の取り方からわかる。取らなかった点は(n-1)^2=O(n^2)個あるので、その回数のクエリで全ての「ペアのペア」を取得できたことになる。

午後6時半終了。これからセミナーの準備もしなければならないのに週記が終わっていないため、TUPC部分は参加記として後から投稿することにし、そのほかの辛うじて書き上がった部分を公開した。

セミナー準備も眠気に悩まされ、日付が変わったくらいでとりあえず終了とした。進捗は微妙。用意できたメモは6ページ程度だから2時間持たない可能性がある。先々週行われた前回のセミナーの時に、次の回は1週休みになった分そこそこ進むことを期待しますと言われたのを覚えている。しかし時すでに遅し。

眠気は十分にあるが眠るのをもったいなく感じてしまい参加記を書き始めた。途中で必要になった情報を得ようとTwitter DMからリンクを踏んだら権限エラーで飛べなかった。どうやら全世界的にTwitterAPIの権限回りが壊れたらしく、t.coドメイン短縮URLを踏むとエラーが返ってくる。リンク文字列が途中まで表示されているように見えても実際は全部短縮URLになっているから、現状どのリンク先にも飛べないというわけ。

午前3時頃に布団に入り、ネット小説を読んでいた。1時間ほどで寝落ち。

03/07(火)

午前9時半起床。昨日せっかくセミナー準備を早々に切り上げたのにその後すぐ眠らなかったのを後悔する程度には眠気がある。時間には余裕があったがその分ゆっくり準備していたので、結局教室に到着するのは5分ほど遅れた。

午前中は同級生の発表。今週から彼もDiestelを読むことになっている。実は春先に早く先に進みたいという理由で1章の後半を飛ばしており、その部分の話題が出てくるたびに少しずつ回収していたのだが、今回彼が担当した部分にも同様の内容があって申し訳ない気持ちになった。

よって今日は1章の該当部分も含めた発表だった。パスの合流を丁寧に観察するためにたくさん場合分けをしていて大変そう。何本ものパスを一気に合流させるから大変なのであって、1本ずつ合流させていけば簡単になるはず。そのことを指摘した。

正午過ぎ、昼食を摂りつつ次回のセミナー日程決め。来週は火曜日にできない代わり別の曜日にセミナーを行うらしい。Muscatキャンプの日程を全力で回避した結果金曜日に決まった。セミナー後すぐオンサイト前泊のため東京に行く予定となるが、何とか頑張りたい。

午後一発目は博士課程の方の発表。数学科なので数式オンリーの説明ではあったが、機械学習の知識があればアンサンブルしているのだと理解できる。ところで結論が「いくつかのモデルをアンサンブルするとそれぞれのモデル単体より精度が良くなった」と言っているように見える。それは……当たり前じゃないだろうか?

発表の終盤から1時間ほど寝ていたらしい。猛省。正確には30分くらいで一度起き、しばらく休憩となったことを聞いてまた寝たのだった。

次は自分の発表。案の定内容が足りず1時間半ほどで終わってしまった。しかし今日終わらせた平面的グラフの平面への埋め込みはグラフ的な話と平面幾何的な話が渾然一体としているから、発表を終えての疲労感はあった。だから内容が薄かったというわけではない、はず。

午後5時半ごろ帰宅。疲れ果ててしばらくTLを眺めることしかできなかったが、一念発起して外出した。

まず仙台駅まで行ってオンサイトのための切符を購入。つけ麺を食べてゲーセンに向かった。チュウニズムデュエルを終わらせたらとっとと帰ろうと思っていたのに、なかなか調子が良くて結局閉店まで遊んでいた。今日の成果は14+のSSS一つと15のSSS二つ。

AirULTIMAは今日初めてのプレイでSSSが出て、2回目でさらに伸びた。3回目ではもう癖がついていてダメダメ。結局「見たまま押す」、といってもぶどう地帯はグシャグシャ擦っているが、ともかくそれしかできていないので、何とかなっているうちにスコアを出すゲームだったらしい。

「Trrricksters!!」は前回ゲーセンに行った日に「もう一回挑戦したら出そう」と言っていて、その通りになった。すでにほぼ噛み合い待ちだったがかなり上手く揃ったと思う。

71小節後半はなぜか今日上手かった。多分フリック階段の速さがたまたま合っていたのだろう。78小節は黄タップを目印に押す手を変えるとよい。81小節からはどのタイミングでどちらの手を連打するか覚える。88小節は座学しているときに外から内へ擦って通す運指を知った。

「Strange Love」はラスクレで出た。これも噛み合い待ちだった。プレイする度7小節・26小節からの配置に癖がついて大変。またラストでアタミスを出して鳥寸を踏むことが多くかなり辛かった。

手元動画を撮っていた。上に挙げた三つ全部撮ってあり、以下のツイートのリプライにまとめられている。鳥寸シーンもツイートしてみた。

ドンキでパン類を買い込んだ。買ったものをリュックに詰める際、スマホアームをゲーセンに忘れたことに気付いたが、戻ったらすでにシャッターが下りてしまっていた。

日付が変わってから帰宅。上のツイート群を行った後シャワーを浴び、しばらく日記を書いて午前4時過ぎ就寝。

明日からMuscatキャンプだが、参加方法についてのメールがまだ届いていない。いったいどうなるのだろうか。

03/08(水)

午前10時半ごろ目を覚ましたらMuscatキャンプのメールが届いていた。それを確認したらすぐ二度寝すればよかったのに、なぜかカクヨムハーメルンを読んでしまい眠れなかった。

午後3時前に布団から脱出して準備し、いよいよキャンプ1日目を開始……と思ったら今日は日本由来のセットだった。解いたことのある問題なので参加を取りやめ、日本からキャンプに参加していた3チームで半から代わりのバチャを走った。中国ICPCのGuangzhou大会。

Dashboard - 2022 China Collegiate Programming Contest (CCPC) Guangzhou Onsite - Codeforces

LEHAMCIを解き7完。自分はAMCIを実装した。今日はチームメイト二人にそれぞれ用事があって、ぷらさんは最初と最後、かっつさんは最初しばらくだけの参加となった。

Lはぷらさん、Eはかっつさん、Hはぷらさん。この辺りはノータッチだった。

Aは2乗の木dp。葉を1個見なくてもよいので見ていない葉が0個か1個かで2種類の値を持つ必要があること、ある頂点のモニターを確認したらそれぞれの子以下の部分木から1個ずつ見なくてもよい葉を選べて、それは全体で見ないことにした葉にはカウントされないことがポイント。それぞれ1回ずつWAを出した。中途半端に気付いてしまったため葉の数が1個のケースをずっと特別扱いしていて、考察を進めるたびに場合分けが減って綺麗だった。

この辺りで二人が離脱したはず。Mの考察ができていて、実装も途中まで進められていたが、以下に述べる理由で一から書き直し通した。

解法は桁dp。和に関する制約があるので、途中まで実装されていた上の桁から見る方法はちょっと大変。そこでARC156Dと同様に下の桁から見ることにした。これで毎回偶奇だけ気にすればよくなる。下の桁からでも桁dpできるというのは知ってはいたが、明確に効く問題はなかなか見ない気がする。

D - Xor Sum 5

Cはすべての頂点uに対し1\rightarrow u\rightarrow nパスがあるという条件から、1\rightarrow uパスの重みL_uが一意に定まらなければならない。この値を決めることを考えた。

まず、辺x\rightarrow uy\rightarrow uが同時に存在する場合L_u=L_x+w_u=L_y+w_uだからL_x=L_yがわかる。この関係で等しいLを持つ頂点を一まとめにした。また辺u\rightarrow vがあればL_v=L_u+w_v\gt L_uがわかる。この大小関係を一まとめにした後のグループ間で辺を張って表現した。

これで自己ループができたりグループ間にサイクルができれば矛盾がわかる。そうでなかった場合トポロジカルソート順に値を割り振ることで上の条件を満たせて、wが復元可能になる。

Iはちょっと面白い。2乗の木dpを全方位木dpにしたくなるが計算量が壊れてしまいできない。そこで連結成分を決めながら根となる頂点も一緒に選ぶことにすると、うまいこと遷移も書けて解ける。

解けたのはここまでで、残り時間はJとKに取り組んでいた。

Jは手で数項計算すると規則性がわかる。整理すると\sqrt{S_i}という値を\sqrt{S_0}=0から負にならないように\pm 1していることになる。a_i=-1\pm 2\sqrt{S_i}から\sqrt Sの上限も求まる。こういうのはよくある問題に見えたが、上下に制限があるとどうしていいかわからない。適当に包除したらWAだった。上限と下限を両方満たさない遷移を引きすぎているようだ。

Kはサンプルが合うように頑張って数え上げる対象を列挙した。まず1辺とその両端点は一直線に並ぶから、追加で1点選ぶ方法はすべてOK。さらに長さ2のパスとその上の端点も一つの平面を定めるためOKで、特に真ん中の頂点以外を選ぶ方法は先ほどカウントしていない。同様の理由で長さ3のサイクルとその上の1点もOK。これは1点を選ぶ方法が3通りある。

これでもまだ微妙に足りなくて、最後に残ったのが長さ4のサイクルだった。この4辺に対応する点の間には線形の関係式があるから同一平面上に乗る。これでサンプルが合った。一応、4点のうち辺の本数が0本から4本まですべてのケースを網羅したからこれで全部だとも考えられる。

数え上げるのが大変なのはC_3C_4だが、検索すると以下のツイートが出てきて、その先をチェックすることでどちらもライブラリがあることを知った。特にC_3は列挙すらできるようだ。しかし貼って出したらMLEして、最後まで解消できなかった。

https://kopricky.github.io/code/Graph/EnumeratingC3.html

終盤ぷらさんが帰ってきてB問題の考察と実装をしていたが、こちらもサンプルが合う前にコンテスト終了。その後通ったらしいのでもうちょっと時間があれば……といったところか。

感想戦。ぷらさんからLとHの解法を聞いた。Lは人を駅に割り振った後駅ごとに並び替えを考えるのではなく、並び替えてから割り振らなければならないという点が少し気づきにくそう。その後かっつさんがいないので二人でEを解いた。1回ボタンを押すたびに誰かを1秒邪魔できると読み替えるのが重要。

感想戦の途中でKが通った。MLEを回避するため、次数の大小で処理を分けるときの閾値をかなり小さめにした。代償として4.9secかかっている。TLは5secなのでギリギリ。

解散後、日付が変わったくらいにJを通した。鏡像法というのを使うと聞いたがわからなかったので詳細な説明をお願いしたら、次のような考え方を教えてもらった。非常に美しい。カタラン数を求めるときに使う最初に対角線をまたいだ瞬間残りを反転するという方法についても、残りではなくこれまでの経路を反転すると思い直せば同様の解釈が可能となる。

カタラン数の場合、自分は残りを反転した後一対一対応を作るという方法を覚えていた。しかし今回はここがうまく作れなくて困ってしまう。こうやってdp配列の値の対称性を考えることを覚えておきたい。

しばらくハーメルンを読んでいたが、そのうちうっかり布団に潜り込んでしまった。午前1時くらいに寝落ち。

03/09(木)

午前4時半起床。また延々ハーメルンを読んでいた。午前9時に二度寝に成功。

正午に目覚ましで起床し、シャワーを浴びて用事のため外出した。まず火曜日ゲーセンに忘れてきたスマホアームを回収。その後指導教員の先生、同級生、博士課程の方というセミナーのメンバーで食事会をした。博士課程の方が無事卒業され3月末に母国に帰国されるのでその記念である。

大町西公園で咲いていた梅をバックに写真を撮り、帰宅。帰り道は博士課程の方と二人きりで、英語でなんとかかんとか会話しながら歩いた。袴・着物・浴衣の違いがよくわからないみたいなことをおっしゃっていたはず。説明を試みるも話すうちに自分でもよくわからなくなっていった。

午後3時前に帰宅し、そのままMuscatキャンプ2日目。ぷらさんが出られなくて二人だった。ちなみにこのキャンプのセットについてはまだ外部での言及が禁止されているから、当然日記にも書けない。そのうち解禁されてから参加記としてまとめたい気持ちはある。

午後6時半からはキャンプを抜けてCF #857 div.1に出た。

Dashboard - Codeforces Round 857 (Div. 1) - Codeforces

Aから詰まってしまった。最終的には要素の重複がない状態ですべての2\times 2部分行列のXORを0にできた。どの2列を選んでも、すべての行についてその行にある要素同士のXORが等しくなればよい。1列適当に決め、他の列をそれとのXORによって決めることで達成できる。適当にやったら同じ要素が出現してしまい1WA。

ちなみに部分行列の一般的な定義では行または列を非連続に取り出したものも考える。上の構築はそれでも条件を満たすが、サンプル出力は満たさない。実際注釈には5\times 5行列の4\times 4部分行列が4個だと書いてあった。しかし連続なものしか考えないということは問題文に書いておくべきではないだろうか。ここを確かめるのにも時間をかけた。

Bはaの最大値を決め打ってbについて考えればよい。ペアとなるaが決め打った値より大きい場合はbを採用するしかない。そうでなくても決め打った値に近いbを持つペアはそちらを採用する可能性があって、setの二分探索で調べるべき定数個を取得できる。

Cはimpressionを得られないアルバムは聴かなかったものとしてよく、この場合聴いたアルバムは最大値の昇順になっているため同様に並べた上でdpすればよい。遷移は列の長さ分時間をかけられるので、アルバム中最初にどの歌でimpressionを得たかをすべて試せる。

Dはよくわからない。頂点番号のほかにこれまで通ってきた中でwが最大の頂点番号も持っておき、パフォーマンスの回数と所持金のペアを距離として最短経路を求めたら通った。所持金が足りなくなるたびwが最大の頂点でパフォーマンスしていたことにしてから遷移するというもの。

Eはsolved数が少なかったが取り組んだら通った。同じ価格だと分かった頂点を新たにマージするのは高々n-1回しか発生しないから、マージしなくてよい頂点を飛ばしながらパスを舐めることができればよい。これは、まずHLDによってパスを分解した後、セグ木上の二分探索でどこまで一致しているか見るという方法で実現できる。頂点のマージをマージテクで行うことでセグ木の更新が可能。頑張って実装した。

自分の実装では計算量の保証が全然できていないことにコンテスト後に気づいた。パス上の区間でその間がすべてマージされているものを探したが、ひたすら同じクエリが飛んでくると全然マージされないので区間の数が全然減らない。正解はマージした集合に番号をつけてそれを頂点に振り、数列として一致する区間をロリハで求めることだったようだ。その実装はキツすぎる。

Fはかなり多く通されていたのに全く分からずコンテスト終了。なぜかEがシステスを通過して無事5完、しかしFが通されすぎてこれでも55位、2960→2930(-30)。RoomのBとCが合計で17個落ちていてびっくりした。OI系のコンテストはpretestが強い印象があったがそんなことはないらしい。

その後はハーメルンを読み進めていた。午後11時頃読了。「とある黒猫になった男の後悔日誌」。

syosetu.org

面白かった。主人公の内心と外面がかなり違うことによる勘違いモノという側面もあるように見えたが、メインは単純に無双だと思う。戦闘で強いだけでなく統治・統率関連でも才能を発揮していて良かった。主人公の口調の慇懃さが少し気になる。丁寧な態度とへりくだる態度は紙一重であると考えていて、後者のほうにちょっと振れて見えてしまった。ちゃんと締めるところは締めるのだが。

しばらく日記を書き、午前4時台はインターンの作業をしていた。ドキュメント整備。操作の様子を録画したりして結構丁寧に作った。想定している読者はわざわざChromeをインストールして使っていたりしないだろうと考えわざわざMicrosoft Edgeを使ったが、これはOBS Studioでウィンドウキャプチャできないらしい。画面ごとキャプチャするしかなかった。

ゴミを出して布団に入り、カクヨムから「大学入学時から噂されていた美少女三姉妹、生き別れていた義妹だった。」を読了。

kakuyomu.jp

読み終えて作者の作品リストを見てから気づいたが、この方の書かれた「貴族令嬢。俺にだけなつく」というラノベを読んだことがある。言われてみればヒロインが主人公をヨイショする様がかなり似ている。どちらも過剰に感じてあまり好みではなかった。

午前8時頃寝落ち。

03/10(金)

正午を過ぎて起床。半から1on1。

いつものように進捗を報告した後来週のタスクについて話した。ドキュメント整備はもうそろそろ終わりにして、そのドキュメントをもとにやってもらった作業の結果を使う準備をしなければならないらしい。とりあえず来週までに最低限整備を終わらせておくことになった。

午後2時終了。今日のMuscatキャンプのセットを確認するとUniversal Cupで使用されたものだったため、水曜日と同じように代わりのバチャを立てて走ることになった。午後3時から開始。

Dashboard - 2017 China Collegiate Programming Contest Final (CCPC-Final 2017) - Codeforces

EACKGJIHを解き8完。自分はCHを実装した。今回のセットはなぜか出力がGCJ形式で、テストケース番号を振るのを要求されていた。

Eはかっつさん。Aは最初自分が読み、完全順列の式を書いて唸っていたが、かっつさんに期待値の線形性からN-1/N\times N=N-1じゃないですかと指摘された。かっつさんはE問題を解いてすでに出力フォーマットの実装が済んでいるため、この問題も書いてもらった。

Cも整理するだけの簡単枠だが結構手間取ってしまった。X\gt Yならお互い1点ずつ取り続けるだけで無限に所持金を増やせる。そうでない場合、セットに負ける場合0対11にするべき、勝つ場合0対9から11対9にするべきで、どちらかの回数を全探索できるためそれぞれチェックすればよい。

Kはぷらさん。実験結果から素早く式が作られていたが、答えが64bit符号付き整数に収まらず符号なし整数を使わなければならないところにハマっていた。自分も読みに行ったもののなかなか気づけなかった。1手で上下左右に2マスずつ広がると考えれば到達可能なマスはおよそ4N\times 4Nの長方形領域(から角を切り落としたもの)と思えて、サイズが16N^2\approx 1.6\times 10^{19}となる。

Gは自分とかっつさんで考えていたがO(NK\log N)にしかならず困っていた。この\log区間取得にかかっている。取得する区間の端点を全体の端にできることがわかり、セグ木ではなくBITを使えるようになったので書いてみようとしていたところ、ぷらさんから各点から遷移できる右端にだけ行くというO(NK)解が提案された。そのまま実装してもらいAC。

後からBITによる解を書こうとしてみたら、単に端点から累積MAXを取っておくことで実現できることに気づいた。こちらもO(NK)になってAC。ちなみにBITを使っても1secで通った。

Jはかっつさん、Iはぷらさんがそれぞれ通した。ここはノータッチでその間自分はFを考え、その後諦めてHに進んでいた。

Hは前セメスターTAをしていた経験が生きた。2次元なら正三角形、3次元なら正四面体状に点を配置すればよい。4次元だと正五胞体という名前になり、その後正単体へと一般化される。よってN+1点が最大で、入力の制約から必ず達成できる。

構築方法としてまず一つ単体を求め座標変換して入力に揃えることを考えたが、高次元の座標変換はよくわからない。よってそちらは諦め次元を一つずつ拡張していくことにした。点がN個以下の場合N次元の超平面に乗っているから、それの法線ベクトルを求め、適切な長さで点たちの重心に足す。これが新しい点となる。

法線ベクトルは、すでに存在する点に関する線形関係式\sum_{i=1}^n a_ix_i+a_{n+1}=0を連立させて解くことで(a_1,\dots,a_n)として手に入る。(x_1,\dots,x_n,1)^Tを並べたN+1行の行列の右側にN+1単位行列を並べ掃き出し法を行うと右側の行列の行ベクトルに現れる、という方法で計算した。

掃き出し法にはO(N^3)かかるため、毎回行うわけにはいかない。ただし対象となる行列は列が一つずつ増えていくだけだから、前回の計算結果を使いまわすことで毎回O(N^2)にまで削減できる。これで合計O(TN^3)

TLは……1sec!とりあえず出したらTLEしてしまった。手元で試すと8secかかって青ざめていたが、CFで実行してみたところ入力なしで1060msだったので希望が見えてきた。vectorを生配列に直し、long doubleをdoubleに変え、pragmaをいくつか足してもう一度出したら900msで通った。

残り時間はDを考えていた。解けた気になって実装を始めたが、\binom{n+i}{k}を巨大なnと連続するiで計算する必要が出てきて時間が足りず放棄。iに関する結果からi+1に関する結果を求めるいつもの方法だとnくらいの数で割り算をする必要があって、法の10^9+7を軽々超えてしまう。

感想戦。Eはまあ簡単枠。Jは牛ゲー、Iはなもりグラフをループと木に分けて管理するかなり面倒そうな問題だった。それぞれ解いてもらえて本当に助かる。またTLで見た他のチームの解法に、Hで足すベクトルを直交補空間の直交基底として一発で全部求めるものがあった。言われてみれば確かにそういう関係になっている。

午後9時20分からyukicoder 380に出た。最近ご無沙汰だったが、今週はかなり競プロ漬けなのでここまで来たら出られるものには全部出ようと考えた。

yukicoder contest 380 - yukicoder

Aは制約が小さいので全探索。式を考えながら書いていたら実は結構きれいな形だということに気付いたが、そのまま書ききったほうが当然早い。Bは貪欲でよい。この2問はFAだった。

Cはしてやられた。愚直を書こうと思ってもどの範囲まで調べれば良いのかわからない。結局手で計算して、5\rightarrow 16\rightarrow 1から奇数が全部2手でできそうだと感づいた。「Nが奇数ならあるkが存在し2^k\equiv 1\pmod Nが成り立つ」と聞けばいかにも正しそうに見える。出したら通った。

Dはダブリング。Hをソートした列の上でTで二分探索したり、結構手数は多かった。

Eは難しかった。包除原理で立式すると、集中精進期間をd\le N日間としたときの場合の数が\sum_{i=0}^d(-1)^i\binom{d}{i}\prod_{j=1}^M{}_{d-i}\mathrm{P}_{c_j}として表される。ここでc_j=\#\{A_i=j\}である。この式を分解するとd!以外はiに関する項とd-iに関する項の積に分解できるので、それぞれ計算できれば畳み込みで求まる。前者は簡単。

問題は後者の\frac{1}{(d-i)!}\prod_{j=1}^M{}_{d-i}\mathrm{P}_{c_j}を高速に求める部分。\sum_j c_j=Nからc_jの値の種類数がO(\sqrt N)通りしかないため、どんな数が何回現れるか集計しておいて、d-iを固定するごとにその集計結果を全部見ることで全体O(N\sqrt N)になる。内側でべき乗を計算したりしているが十分高速だった。

Fは結構すんなり解けた。A_1\gt 1またはB_1\gt 1なら1が答え。そうでない場合どちらかのデッキから取り出せる数は答えにならない。逆にそうでない数、つまりk\notin A\cup Bに対する[k^2,(k+1)^2)が答えの候補になりそう。

そのようなkのうち最小のものを取ってきたとき、この区間素数が含まれていればそれが答えの上限となる。多分あるだろうと思ってプログラムを書いて試してみると確かに存在し、しかも最小のものはk^2に十分近いところにあると分かった。よってk^2からその素数までを全探索し、それぞれ約数全列挙してチェックすることができる。出したら通った。

Gは難しかった。こういうシチュエーションの期待値に関する事実があったことを思い出し、「一様分布」「最小値」「期待値」で検索して出てきた以下のページを眺めながら考えていた。

最大値と最小値の分布(一般論と例) | 高校数学の美しい物語

x\gt yである確率をP(y)と置くと、これはどんな経路を通ってもy以下の数が高々1個しか存在しない確率に等しい。サンプル1の2\times 2マスの場合、y以下の数が出現するマス数としては0個、1個、または左下と右上の2個というケースしかない。それぞれ確率は(1-y)^44\times y(1-y)^3y^2(1-y)^2である。足すとP(y)になるはず。

スコアの期待値を計算するためには、xが特定の値である確率を知る必要がある。xの累積密度関数1-P(y)微分すれば得られる。それにy^Kを掛けて0\rightarrow 1積分することで答えが求まる。上の例をWolfram|Alphaに投げると確かに13/30となった。

あとはP(y)の計算。T=\min(H,W)と置くと、y以下の数が出現するマス数c0\le c\le Tを満たす。またc個のマスをどの二つも右下への経路に同時に乗らないように配置する方法は、c行とc列を決めて左下から右上に並ぶようにするしかないので、\binom H c\binom W c通りあると分かった。これにy^c(1-y)^{HW-c}を掛けて足し合わせたものがP(y)となる。

このあたりでコンテストが終了したがそのまま実装を続けた。多項式を直接計算するとサンプルがあったもののTLE。さすがにHW次の式は扱っていられないようだ。和の形に分解したまま計算する場合は、cごとにy^c(1-y)^{HW-c}微分し、y^Kを掛け、積分できればよい。手計算とWolfram|Alphaを組み合わせて何とか閉じた式が得られた。

まだ(HW+K)!くらいの階乗が出現して組み合わせ計算のライブラリを貼っていては間に合わなかったが、分母分子で打ち消しあって狭い範囲の積しか残らないようで、そこを丁寧に扱うことで爆速になった。30分遅れで無事AC。

コンテスト自体はFまでの6完で、writer・testerを除くと5位。Gの解説を読むと(1-P(y))'y^KではなくP(y)(y^K)'積分していてびっくりした。これでもよいことの直接的な理由は分からないが、maspyさんに部分積分P(1)=0を使うことで同じ式になると教えてもらった。

03/14追記:writerの方から教えていただいた。

食事してから迂闊にもカクヨムを読み始めてしまった。午前3時頃「【悲報】売れないダンジョン配信者さん、うっかり超人気美少女インフルエンサーをモンスターから救い、バズってしまう」を読了。

kakuyomu.jp

配信やコメント・掲示板の描写にやけにリアリティがあって辛い。現実のVTuber・配信者に関するネタがポジティブ・ネガティブ問わず盛り込まれていて、読んでいて微妙な気分になるシーンがいくつかあった。しかし話の内容・展開自体が面白かったため、それらの要素を飲み込んで読み進めていけた。主人公が気弱そうなのにちゃんと無双していて嬉しい。ダンジョン探索者としても、配信者としても。

シャワーを浴びて日記を書き、午前6時に布団に入った。何を考えたのかハーメルンで1時間弱溶かしてから就寝。

03/11(土)

午後1時半に目覚ましで起床。今日はMuscatキャンプが休みだが代わりにUniversal Cupがある。日程の被りが見事に回避されていていかにも全部参加してくれと言っているかのよう。

Universal Cup 7回目でZaporizhzhiaセットだった。今回は、少なくとも解いた範囲では考察の難しさのわりに実装が簡単な問題ばかりだった印象。

The 1st Universal Cup. Stage 7: Zaporizhzhia - Dashboard - Contest - QOJ.ac

チームでEKGHIMJDを解き8完、53位。自分はKHJの考察+実装に加え他のいくつかの問題でも考察に参加した。

かっつさんがEを通している間にKを考える。n=2で実験すると、次のような行基本変形ができた。上の行から順に見て、下の適切な行から引いている。この操作で行列式の値は変わらない。

\displaystyle\begin{pmatrix}
a_0&a_1&a_2&a_3\\
a_1&a_1&a_3&a_3\\
a_2&a_3&a_2&a_3\\
a_3&a_3&a_3&a_3
\end{pmatrix}\rightarrow\displaystyle\begin{pmatrix}
a_0&a_1&a_2&a_3\\
a_1-a_0&0&a_3-a_2&0\\
a_2-a_0&a_3-a_1&0&0\\
a_3-a_0&a_3-a_1&a_3-a_2&0
\end{pmatrix}\rightarrow\displaystyle\begin{pmatrix}
a_0&a_1&a_2&a_3\\
a_1-a_0&0&a_3-a_2&0\\
a_2-a_0&a_3-a_1&0&0\\
a_3-a_1&a_3-a_1&0&0
\end{pmatrix}\rightarrow\displaystyle\begin{pmatrix}
a_0&a_1&a_2&a_3\\
a_1-a_0&0&a_3-a_2&0\\
a_2-a_0&a_3-a_1&0&0\\
a_3-a_1-a_2+a_0&0&0&0
\end{pmatrix}

右下三角形が0になったので、符号に気を付けながら余因子展開を行えば行列式が求まる。右上から左下への対角線上にある成分は、添え字をbitの集合と見てある集合の上位集合すべてを符号を入れ替えながら足しているとエスパーできる。これはゼータ変換っぽい感じで求まる。

Gの考察に参加した。条件を式で書き移項するとa_1+a_n=a_2+a_{n-1}=\dotsが得られて、ここからnが偶数の時はすぐわかる。aをソートして両端からペアにしていけばよい。nが奇数のときどうなるかちょっと悩んだが、中心の要素が二つにコピーされると思えば偶数のケースに帰着できた。実装はかっつさんに任せた。

Hを考えていた。Gが単なるサイクルのとき、同型なグラフの個数は円順列の数と一致するから、n\ge 5ならNO。次にGがサイクルを含む場合も同様のことを考えて、同様にn\ge 5なら必ずNOになると思い込んだ。後述するようにこれは間違っている。

とにかくサイクルを含むケースの処理が終わった。n\le 4での場合分けは複雑なので、この範囲は全探索することにした。よって残りはn\ge 5かつGが森である場合。

同型でない二つの木が存在すると必ずNOになることが言えた。すべての木が同型である場合も木が複数あるとNO。正確には1頂点の木がn個あればYESだが、今m\ge 1なのでそれは考えなくてよい。

最後に残ったのがGが木である場合で、これは葉とその親を二組固定するとそこだけでn通り以上の頂点番号の入れ替え方を作れそうだった。これもNO。

結局n\le 4は全探索、n\ge 5はNOとして提出した。しかしWA。実は3ケースだけ特別扱いをする必要があって、それぞれペナを出して4回目でようやくACできた。

特別扱いするべきだったのは、完全グラフ、完全グラフ+孤立点、ウニグラフ。まずウニグラフはGが木でありかつ「葉とその親を二組固定」ができないケースだった。完全グラフ+孤立点はこの補グラフで、完全グラフは「1頂点の木がn個」の補グラフ。これ以外を特別扱いしなくてよい理由はわかっていない。

Iも考察に参加した。1回目にどの順で頂点を取ったか固定し、その順で頂点を見ながら2回目の操作を挿入dpっぽく考えることで、被ってしまう操作の回数を数え上げる。これまでk点取ってk+1点目を考えているとき、それを1回目と同様k+1点目に取るなら辺の張り方は2^k通りあるが、もし1点目に取るなら2^0通りしかない。

その間も足し合わせ、合計2^0+2^1+\dots+2^kk点目までの値に掛けることでk+1点目までの値が求まる。この計算をあらかじめ行って途中の値を保存しておけば、クエリごとに定数時間で答えが出せる。実装はぷらさんにお願いした。

Mはかっつさんが取り組んでいたがWAが出て直っていなかったため、自分も問題と実装を読んで考えてみた。最初は使用するボールの個数を疑っていたが、一周期にかかる秒数をnで割ったもの、つまり一周期で列を何周するかを使用する現在の実装が正しいことに納得できた。

次にどちらの手を使うかを疑ってみた。nが奇数のとき同じインデックスでもループするたびに偶奇が変わってしまうことがポイントに見えて、そのあたりで考えていると、片方の手だけ使うと判定されたボールでも一方の手に集中するのではなく両方の手に半分ずつ分かれるということに気づいた。このコーナーケースを伝え直してもらったら無事通った。

Jはrollbackを使えるなら使って全コイン賭ける、使えないなら1コインずつ賭ける、という戦略が最適だと予想。最悪ケースではm回でrollbackを使い切り、所持コイン2^m枚の状態でn-mターンしのぐ必要があるので、2^m\lt n-mなら答えは「破産」になる。

そうでない場合、どのターンでrollbackを使い切るか、使い切らないならnターンで何回使うかを変数において立式してみた。

前者についてkターンだとすると確率が\left(\binom{k}{m}-\binom{k-1}{m}\right)\times\frac{1}{2^k}であり、所持コイン枚数についてはkターン目の2^k枚以降期待値的には変化しない。掛けてm\le k\le nで足すと\binom{n}{m}が得られる。

後者についてk回だとすると確率が\binom{n}{k}\times\frac{1}{2^n}であり、所持コイン枚数は必ず2^n枚となる。0\le k\lt mで足し上の値も含めることで\sum_{k=0}^m\binom{n}{k}が答えとなった。マルチテストケースなのにmの総和にしか制約がなかったのも納得。これでサンプルが合い、そのままACした。

Dも考察に参加した。右下で2回ほど余因子展開することで漸化式A_k(x)=xA_{k-1}(x)-b_kA_{k-2}(x)が得られる。ここからゴリゴリA_9(x)くらいまで計算した結果、b_1+b_2=b_3+b_4=b_5+b_6=b_7+b_8=0b_1+b_5=b_5+b_9=0という関係式を手に入れた。

しかし規則性が見えない。すでに得られた関係をもとに項を消去しているから複雑なんだと感じたため、そのまま計算してみたところ、なかなかいい感じの表現が見つかった。

A_k(x)x^{k+1}次式で、[x^k]A_k(x)=[x^{k-2}]A_k(x)=\dots=0[x^{k+1}]A_k(x)=1[x^{k-1}]A_k(x)=b_1+\dots+b_k[x^{k-3}]A_k(x)b_1,\dots,b_kから「添え字が隣り合わないように」二つ選んで掛け合わせたものすべての和になる。[x^{k-5}]A_k(x)の係数はそれを三つ選んで行ったものになる。以下同様。

この表現を考えることで計算が楽になった。三つの積まで観察し、上で求まった類の式から増えないことを確認してかっつさんに実装に入ってもらったが、その後計算を続けていくうちに四つの積に関する式b_1b_3b_5b_7+b_5b_7b_9b_{11}=0が見つかった。上の式を用いて整理することでb_3+b_{11}=0が得られる。

さすがにこれ以上はやっていられないが、計算の途中で2べきっぽさは感じ取っていたため、おそらく次の式はb_1b_3b_5b_7b_9b_{11}b_{13}b_{15}+b_9b_{11}b_{13}b_{15}b_{17}b_{19}b_{21}b_{23}=0となるだろう。これも整理するとb_7+b_{23}=0と綺麗な形になる。添え字の差が4、8、16と増えているのもそれっぽい。これで改めて実装してもらったら通った。

残り時間はAとLを眺めていた。Aは実験結果からm素数ならm\bmod 4で場合分けして解けるが、それ以上のことはわからない。平方剰余で検索しても特に進展はなかった。Lはそもそもm辺のDAGを数え上げるのすら難しそう。一応OEISにあった。

A081064 - OEIS

感想戦。Eはいくつかの場合分けで解けるようだ。LRが両方偶数の時に作れないのはちょっと面白かった。他の問題については上にほとんど書いたので省略。

Hの3ペナは大反省だった。補グラフにも注目すべきということを1ペナ目くらいにはわかっていたはずなのに、ウニグラフとその補グラフで1ペナずつ使っているのが意味不明。コーナーケースを1個見つけた瞬間狂喜乱舞して提出せずにはいられなくなってしまう。

実は両親が仙台に来た。19時まで対応できませんと伝えてあって、コンテスト終了後部屋に招き入れてからも感想戦のためさらに待たせてしまった。駆け足で終わらせたが20分くらいかかり、その後ABCに間に合うよう急いで外食に出かけた。

今日はココス。ちょうどにじさんじとのコラボキャンペーンをやっていたが、特典のクリアファイルは売り切れだった。期間終了も間近だし仕方ない。

帰宅してすぐABC293に出た。まだ親がいるので今日は実況はなし。

AtCoder Beginner Contest 293 - AtCoder

Aはsedで2文字ずつマッチさせ、それぞれキャプチャして入れ替えたものに文字列置換することで実現できる。

Bは問題文を読んでいなくて\{1,\dots,N\}\setminus Aを出力しようとしていた。しかも提出欄にRubyコードを直接コーディングしたところtypoがあって2RE。ちゃんと手元で書こうとしたタイミングでようやく問題文が思っていたのと違うことに気づいた。C++で実装。

Cは\binom{H+W-2}{H-1}通りの経路をbit全探索で生成しそれぞれチェック。dfsのほうが途中でチェックを行えて速いだろうがこちらでも問題なく通った。

Dは頂点を倍加して赤の端、青の端に対応させ、入力の通りに繋いだ。すでに繋がっているロープの両端点を結んだときに答えのXをインクリメントしておけば後から閉路のチェックをしなくてよい。

Eは\frac{A^X-1}{A-1}に書き換えてから割り算ができないことに気づきしばらく固まっていた。結局書き換え前の形で考え、X\leftarrow\lfloor X/2\rfloorとしたときの解をずらして足し合わせれば二分累乗法っぽいことができると気づいてAC。

Fは難しかった。bを適当な範囲で全探索したいから、b進法で表記したときの桁数が小さいものは直接計算することにした。1桁はありえない。2桁ならb=N,N-1である。3桁なら2次方程式を解いて4通りの解候補が得られる。4桁は……やっていられない。このままではO(T\sqrt[3]N)かかってしまう。

そこで適当な数Bについてb\ge Bかつ4桁以上で表現可能なNをあらかじめ全列挙しておくことにした。106まで見ればいいのでなんとか間に合う。あとはクエリごとに2\le b\lt Bかつb^3\le Nの範囲で全探索すれば求まる。B=1000で出したら2secかかったが通った。

GはAに出現する回数が多いものと少ないもので処理を分けた。具体的には、W回以上出現するものはそれだけ集めてクエリを一つ一つ計算、それ以外はまとめて計算。

後者の具体的な方法は、k=1\dots Nの順に見て、A_i=A_kなる1\le i\lt kに対しBITのi番目に\#\{i\lt j\lt k\mid A_j=A_k\}を足しておくというもの。クエリ(l,r)に対してはk=rの処理が終わったタイミングでBITのl番目以降の総和を答えればよい。毎回O(W\log N)かかる。

最初は前者の計算時に抜き出したインデックス上の二分探索を行っておりO(Q\log N)かかっていた。W=500として提出しTLE。この二分探索の代わりに毎回O(N)かけてすべて計算しておき、W=200としたら1secで通った。

Exはまず木dpで直接答えを求めようとし、二分探索が必要なことに気づいてdpの遷移を書き直していたら時間が足りなかった。30秒遅れで書きあがったものを提出するもWA。

7完70位。Dは頂点を倍加する必要がないらしい。Fは3桁以上ならbが高々一意であるようだ。そういうことを考えた気もするが、なぜかたくさんあると思い込んでしまった記憶がある。Gの想定解はMoだった。

コードゴルフ。AはVimで「カーソルの下の文字を削除→カーソルの直後に追加→カーソルを右に移動」をループすれば解けて、12Bでsedの文字列置換19Bより短くなる。午後10時くらいに気づいて提出しておいたが、コンテスト開始直後に同様の提出があって負け。

また日記を書いているときに確認したらbashにも12B解があった。ddコマンドのオプションでconv=swabを指定すると2バイトずつペアにされて入れ替えられるようだ。これは太古の昔、エンディアンが異なるデータを扱うために使用されたらしい。

history - Why does `dd` have `swab` functionality - Unix & Linux Stack Exchange

BはAWK。フィールド変数を書き換えながらループすることで、最終的な$0は呼ばれなかった番号が昇順に並び間が穴あきになった文字列となる。これを$0に代入しなおすとNFが現在のフィールド数、つまり呼ばれなかった番号の数に更新されるので、わざわざカウントしなくてもよいというもの。結構改善が残っていて負け。

CはRubyでdfs。既出の要素はhashに0を入れておくことにして要素が重複した時の返り値にしたり、盤面の外に出ないかチェックして再帰呼び出しするところまでを条件式と捉えて終点のチェックを1回しか行わないようにしたり、細かな改善が結構うまくいった。

Dは入力の制約から通常の閉路検出より実装が軽くなる。常に「ひとつながりのロープにおけるもう一方の端」を持っていると考えることで、ロープを結ぶ操作がDancing Linksと同様にして行える。Rubyで書いたらPerlで縮められたが、AWKで書いたらさらに縮んだ。

Eはdc。解説にある\bmod{(A-1)M}で計算してA-1で割る方法に仰天。何度も見たのにまた忘れ去っていた。これをdcで書いた。0で余りを取ろうとすると演算自体が行われなず、スタックの中身が通常とずれるのを利用することでA=1の場合分けが行えた。

以降は手付かず。

Exをupsolveした。部分木の根と同じ色を今見ている頂点にも塗れるか、塗れないかで2状態持った。子の数の2乗で計算するコードを書き答えを合わせてから1乗に落とした。かなり大変。

Submission #39650680 - AtCoder Beginner Contest 293

maspyさんの実装が簡潔と聞いて見に行った。今見ている頂点に塗った色に関する次数を持ってdpしているようだ。子をいったん全部集めると遷移の際に「子のうち値が大きいほうから二つ」みたいなものが欲しくなるが、この捉え方なら自然に書けるということには見覚えがある。今回はそこまで思い至れなかった。

Submission #39622473 - AtCoder Beginner Contest 293

日記を書いて午前7時前就寝。

03/12(日)

午後2時半起床。食事して午後3時から5時間Muscatキャンプ4日目に出た。

今日はかっつさんが用事で不在のため二人……と思っていたが、かっつさんも合間を縫って読解と考察に参加してくださっていたようだ。途中誰も読んだ覚えのない問題の概要と考察がHackMDに書かれていて、ぷらさんと二人でびっくりしていた。

午後8時に終了し、しばらく感想戦をして解散。食事して午後9時からARC158に出た。

AtCoder Regular Contest 158 - AtCoder

Aから大変だった。操作を+0,+2,+4に読み替えたのが敗因だったらしい。偶奇の条件をチェックした後2で割ることで+0,+1,+2をする問題になる。和が3ずつ増えるので、もともとの和も3の倍数である必要がある。ここから先に進むのに30分かかった。二分探索を考え操作回数を固定しても判定関数が書けない。それっぽいものでサンプルが合ったので投げたがWA。

結局場合分けと貪欲で通った。最小の要素に+2、最大の要素に+0するのを三つのうち二つ以上が揃うまで行う。揃ってからの操作はどこが揃っているかでそこに+0+1+1+0をするか+1+2+2+1をするかを変えるだけ。和が3の倍数という条件からこの操作でいつか必ず揃えられるし、絶対に必要なことしかしていないから最適。

Bはすぐ解けた。式を分解すると\frac{1}{x_ix_j}+\frac{1}{x_jx_k}+\frac{1}{x_kx_i}となる。選ぶ数の符号を決め打ってみると各項の符号も分かって、項の絶対値を大きくするべきか小さくするべきかが定まる。それに応じてできるだけ絶対値が大きい・小さい値を使えばいいので、正負それぞれ候補は高々六つしかない。取り出して全探索。

Cもすんなり解けた。桁ごとに分解して考える。10^kの位を考える際、数を\bmod{10^k}でソートしておくことで、ソートした列のどの範囲の数と足したら繰り上がりが起こるかが決まる。繰り上がりが起こる範囲と起こらない範囲でそれぞれ10^kの位の数字をカウントしておき、それを見て答えればよい。

Dは解けなかった。左右で式の次数を合わせるためx+y+z\equiv 1としたいと考えあれこれ試していたがどうにもならず、pが小さいケースで試したところそもそもそのような解が見つからないことを知って絶望。順位表や点数を見る感じEにもチャンスがありそうだったので、そちらに進んだ。

Eは見た目的にDより解けそう感があって、実際解けた。分割統治。マスとマスの間で縦に切ると、パスがその境目を1行目と2行目のどちらで通るかが一意に定まる。左右それぞれ両方のケースに対する答えを求めておく。

境目の左のあるマスでL_1L_2、右のあるマスでR_1R_2だった場合、L_1+R_1\le L_2+R_2\Leftrightarrow L_1-L_2\le R_2-R_1なら1行目で通るとわかる。左右で分離した式が得られたので、それぞれ求めてソートなどしておくことで計算できる。

寄与の係数を間違えているのになかなか気づけず、通ったのはコンテスト終了6分前だった。ギリギリ。結果は4完遅めの102位。

今日は実況を撮っていた。この後のCFまで間30分空いているのを振り返りで埋め、一つの動画として投稿する予定だったが、思ったよりARCが不出来だったのでたくさん話す気分になれない。手短にまとめていったん録画を終了した。

午後11時半からCF combined。今日はサイトが不調なのか提出が失敗しがちだった。再提出する前に本当に提出が失敗していたか確認を挟むとさらにページ読み込みの待ち時間が嵩んで苦痛。

Dashboard - Nebius Welcome Round (Div. 1 + Div. 2) - Codeforces

Aは何も考えず直前の移動も持つBFSを書いた。コンテスト後に改めて考えると、途中までジグザグ、残りは休みながら真っすぐ進むのが最適とわかり、|a|\le|b|として|b|+\max(|a|,|b|-1)が答えになった。

Bは同じワクチンパックを使う人が区間になっているとしてよく、人lからrまでが一つの区間に入れる条件がt_l+d+w\ge t_rと書ける。各lに対して最大のrを求め、その(l,r)だけ使う遷移のdpをした。後から貪欲でよいことを知った。

Cはf=qn+rと表示して\sum_{i=1}^f i\bmod nを計算するとn(n+1)/2\times q+r(r+1)/2となった。よってq=2とするのとq=0とするので値が変わらないから、(q,r)=(0,0)が許されないことを考えても1\le f\le\min(2n,p)の範囲で全探索すればよい。

Dはかなり難しかった。最小化のほうは11を貪欲に二人部屋で埋めてよい。足りない場合は残り一人部屋を埋めるだけなので必ず可能、足りた場合も一人部屋が十分な個数あるので調整が効き、矛盾が生じることがない。

最大化も実は000110を貪欲に埋めればよかったらしいのだが、なかなか納得できなかった。左から順に一人部屋も使いながら貪欲して1WA、実装ミスでもう1WA。時間も30分以上かかっていた。

Eはそこそこスムーズに解けた。ループであってグラフの全頂点との距離が1以下になるようなものが必要で、それがあればループに適当に向き付けたあと残りの頂点からループに向かうパスをなもりグラフのように作っておけばよい。

ループの列挙は普通に書くと始点・終点・通った頂点集合のn^22^n状態持つ必要があって、遷移m=O(n^2)を込めて計算量O(n^32^n)になる。ここで始点をループの中で頂点番号が最も大きな頂点と固定すると、見るべき状態をかなり削減することができた。具体的には\sum_{u=0}^{n-1}m2^u=O(n^22^n)の計算量。

計算量が悪い状態で一回提出しているが、こちらはそもそもループの復元にミスがあってWAだった。

Fは解けず。適当に選んだ1点から最も遠い頂点までの距離Lを求めると、それがd(G)/2\le L\le d(G)を満たすことはすぐ気づけた。二つ目の不等号は自明で、一つ目についてはどの2点も選んだ頂点を経由することで必ず距離2L以下になることから従う。

この値をどうにか管理しようとしていた。最初に距離を求めたとき、使った辺を記録すると木になって、あとは木に辺を追加しながら最遠点を求め続ける問題になる。いかにもありそうだが、少なくとも手持ちの道具では不可能。直径はそう簡単に短くならないのではと考え、再計算するまでの間隔を指数的に伸ばす方針はWAだった。

適当にパラメータを弄って提出し、落ち続けるうちにコンテスト終了。5完遅めで順位は200位ちょっとだった。2930→2829(-101)。

Fをupsolveした。手に入れた値の上限が2d(G)ではなくd(G)であることのうまい利用方法が見つからなかったが、あったらしい。

i\lt jに対しd(G_i)/2\le a_i\le d(G_i)d(G_j)/2\le a_j\le d(G_j)が見つかっている状態でa_i\le 2a_jが成り立つ場合、d(G_i)/2\le a_i\le 2a_j\le 2d(G_j)となってクエリi\dots jの答えを全部a_iにできる。クエリを半分に分割しながら計算する必要がある部分だけ再帰的に求めることで十分高速になる。

ARCとCFの動画を投稿した。今日のARCのwriterであるmaspyさんにかなり詳細に見ていただいて恐縮している。

www.youtube.com

www.youtube.com

日記を書いて午前7時頃布団に入った。なぜかハーメルンを開いて1作、「トム・リドルをTSヒロインにする暴挙」を読了。といってもまだ3話しか連載がない。視点人物がトム・リドルでなくびっくりしたが、それもなかなか乙なもので面白かった。

syosetu.org

午前8時前就寝。今週は5h 4回半を含む34時間ちょっとコンテストに参加していた。

週記(2023/02/27-2023/03/05)

02/27(月)

午後0時半に目覚ましで無理やり起き、大学に向かった。昼食を摂りラノベを受け取って帰宅。

前回受け取ってから10日ほどの間に新しく14冊が入荷していたが、特に今日入荷したMF文庫Jの新刊「Vのガワの裏ガワ」2巻をいち早く手に入れたくて、頑張って営業時間内に起きたのだ。いち早くと言っても発売日は02/25だったからすでに土日を挟んでいる。このタイムラグは購買で受け取る以上仕方のないこと。

帰宅したのが午後2時。今日は深夜からCF combinedがあり、明らかに睡眠時間が足りないのでどこかで仮眠を取りたい。さらに先週の週記も書く必要がある。インターン先定例会は動かせないので、その前と後でそれぞれどちらかを行うことになりそうだ。より長い時間を確保できる定例会後に仮眠を取ることにして、今は週記を書き始めた。

午後4時半から定例会。先週の進捗はあんまりない。コードをちょっと書き換えただけ。今週も今のところはそんな感じのタスクしかない。この定例会だったり1on1だったりで会議の時間だけは一丁前に長く、人件費的な意味での申し訳なさというのが少しある。

勉強会は透過型電子顕微鏡の話だった。今日の発表者の専門分野なので導入は知らないことだらけで戸惑ったが、本題はアルゴリズム的な話で結構面白かった。発表自体は結構短めで、そのあと質疑応答が念入りに行われた。スライドが丁寧だったので素人なりに質問の端緒を見つけられ、それを聞くことで理解をある程度深められたと思う。自分だけでなく他の人の質問もかなり参考になった。

午後6時半ごろに終了。それから1時間くらいしてようやく週記が書き上がった。相変わらず校閲はできていないが、ともかく投稿。すぐに布団で仮眠を取った。

午後11時起床。手元を撮る環境を整え、半からCF #845 combinedに出た。

Dashboard - Codeforces Round #854 by cybercats (Div. 1 + Div. 2) - Codeforces

Aは1\dots nのpostは後ろに追いやられる一方なので、新規で何種類のpostにactionがあったかカウントし、増えたタイミングで代わりに押し出されたものをチェックすればよい。TL 1secだがnmも少し小さめなのでsetで十分高速。配列で線形時間になることには気づいていなかった。

B。最初から揃っているケースは先に取り除いておく。もしaに1が含まれる場合全要素を1に揃えることになるが、どこかのタイミングでn-1要素が1になると以降どうやってもaが変化しなくなるので不可能。逆にそうでない場合、aの最大値を最小値で割るということを繰り返せばどんどん値が小さくなるのに2未満にはならないのでそのうち揃う。操作回数は高々\sum\log_2 a\le 30n回で制約に合う。

Cは難しかったがサンプルが強くて助かった。サンプル出力を眺めると二つ方針があることに気づける。一つはできるだけ左右対称にするもの、もう一つは最小の文字を右端に置いた後残りをソートして左にくっつけるもの。辞書順で小さいほうから何種類かの文字を前者によって並べ、余りを後者で並べたものしか答えにならないようなので、全探索できる。

D1は簡単。二つのCPUでそれぞれ直近に実行したプログラムの番号を持つdpを考えると、a_iを実行しようとしているとき二つの番号の片方は必ずa_{i-1}なので、見るべき状態数がO(k)個になって間に合うというもの。2次元配列でdpするコードを書いて出したら800msを超えてびっくりした。シーケンシャルでないアクセスばかりで定数倍が悪いのだと思う。

D1をセグ木に乗せればD2も解ける。1点更新・取得、全体加算・MIN取得しかしないので、遅延セグ木ではなくセグ木で実現できる。D1の実装を愚直に翻訳したため二つのCPUのどちらがa_{i-1}を実行した直後かでセグ木を2本持ったが書きあがってみると全く同じ操作をしていた。「直前にa_{i-1}を実行しなかったCPUの状態」を持っていると考えれば1本にまとめられたようだ。

D2の実行時間が300msを切ったのでD1をリサブするか結構迷ったが、最終的にはそのままにしておいた。900msはかかっていないため大丈夫だろうと判断した。ちなみにこの問題は線形時間で解けるようだ。セグ木に書き込む値が小さくなる一方だから、特に工夫せず全体MINの更新ができる。

Eは結構面白かった。最短距離がマンハッタン距離と等しいという条件から、同じ行または列にある塗られた2マスの間はすべて塗られている必要がある。実はこれで十分だった。ある塗られた2マスが連結ならその間に塗られたマスによるパスがあるが、そのパスでもし遠回りしているところがあれば必ず一直線にショートカットできて、それを繰り返して最終的にマンハッタン距離で移動するパスが得られる。

そのように塗って自然に連結成分が一つになればよい。そうでない場合、連結成分をぴったり含む矩形が左上と右下あるいは右上と左下に分かれて位置している。前者について考えると、二つの連結成分を繋ぐようなパスを作った場合、左上の矩形についてその右下マスから1マス右または下は必ず塗られることになるとわかる。右下の矩形の左上マスについても同様。

逆に、どちらが塗られるかを決め打ちそれを最短距離で繋ぐことで答えの候補が定数個得られる。これを全部試せばよい。盤面を埋める際は変化しなくなるまで愚直にループを回した。1回にO(nm)かかるループがO(nm)回回るが、nmの和に上限があるので間に合う。そもそも変化しなくなるまでにそんな多くの回数がかかることはないだろう。

順位表を見てGに進んだ。同じチームの人をあらかじめまとめておくと箱根駅伝dpができる。ただ票や投票先をどのように区別するかが問題。

自分は投票先としてラベルiの箱がc_i個あると思い、これを並べることでいろいろ区別した。今票を入れようとしている箱とこれまでで保留している箱それぞれでどのように並んでいるか決めておけば、実際に入れるときは先頭からどんどん使っていくことで必要なだけの区別ができる。この場合票についてはどれを使うかは考えてもどの順番で使うかは考えない。

あるチームについて遷移するとき、cをまとめて前計算しておくことでチーム内での票の割り当ては計算できる。実際にdpを書いてみると状態数O(n^2)に対してそれぞれチームの人数とcの総和の積だけ遷移先があり全体O(n^4)になってしまったが、ちゃんと枝刈りして手元で試すと爆速だった。提出したら通った。

Fは面白かった。aを降順にソートしておくと、あるdについて先頭からd個は両方の操作が行われ、続く(k_1-d)+(k_2-d)個は片方の操作が行われ、残りはどちらの操作も行われないという状態しか最適にならないとわかる。このdを全探索する。真ん中の部分も貪欲で解こうとして操作1を優先するべき値と操作2を優先するべき値を考えていたが、うまい条件は見つからなかった。

ここでn\le 5000なのに目を向けdpすることにした。普通にやるとdを決め打つごとにO(n^2)のdpをすることになるが、dを降順に探索すれば以前の結果から毎回O(n)で差分更新できる。なぜかというと、真ん中の部分はdが1減るごとに左右に1ずつ広がるのみだから。以前の結果から抜くことになる要素が存在せず、単に要素を2個追加したものと思えるのだ。

Hには20分ちょっと残せたが解けなかった。最後まで残る頂点を決め打ち、そこから木dpで場合の数を求め、最後にs_kで割れば答えが求まるということを考えていた。しかし木dpで何をすればいいのかがわからなかった。

コンテスト後もしばらく録画を続け、システス結果を確認しながら各問題の振り返りをしていた。無事全部通って25位、レートは2914→2960(+46)。自分ではかなりうまくいったと思っていたが案外渋い上がり幅だった。その後動画を投稿した。

www.youtube.com

明日はセミナーがないから今すぐ準備する必要もない。昼受け取ってきた「Vのガワの裏ガワ」2巻を読み始めた。大切に大切に読み進め7時間くらいかけて読了。この巻も非常に面白かった。1巻が好みだった作品でも2巻を待つ間に期待だけが膨らみすぎて読んでみると思っていたより面白くなかった、という経験が何度かあるが、この作品はその膨らみ切った期待通りの面白さで最高だった。

この面白さがどこから来たかというと、やはり魅力的なキャラたちのワチャワチャした日常描写からだろうと思う。1巻の前半も思い返せばそういう感じだった。2巻では新キャラとの話がメインに据えられつつ1巻からのキャラにもちゃんと出番があって、全体的に日常シーンの量が増えており大満足。ストーリーももちろん良かったがやはり自分から見たメインはこちらかなという感じ。

主人公がセンターパートという髪型から偏見を受けていて笑った。確かにイケイケの大学生というか……自分にもこの髪型に対する偏った見方がある。画像検索すれば同じ感想を抱く人も少なくないのではないか。ラノベ主人公としては珍しいビジュアルだと思うが、超人気イラストレーターという設定を考えればはまり役のうまいデザインに見えてくる。

シャワーを浴びてゴミを出した。AHC018のレート更新が来ていた。493位、パフォーマンス1253、2030→2031(+1)。また次回に期待。

正午から1時間ほどインターンの進捗を産んだ。コードをちょっと書き換えた後、それに合わせてドキュメントを少し整備した。

それから大学に向かった。昼食を摂ってから購買に向かうと閉店していてびっくり。今日は決算業務か何かがあるようで普段より閉店時間が早まっていたらしい。あと10分早ければ間に合っていたので残念。

床屋で散髪した。座っている間ほぼずっと眠っていて申し訳ない。首をガクガクさせたりはしなかったはずだが、気づくと首を深く俯かせていることが多かったので、やりにくかったと思う。

午後3時頃帰宅。2時間後から1on1が予定されているので、仮眠などはせず起きて日記を書いていた。

1on1は先ほどの進捗を報告した後、次やることの導入。これまで書いていたドキュメントはツールの設定を行うプログラムを動かすためのもので、次はツールを使うためのドキュメントを書くらしい。盛り込みたいことはほとんどこの1on1で列挙できたので、清書をするのがタスクになった。1時間半ほどで終了。正直眠気が限界だったので早めに終わってもらえて助かった。

午後7時前就寝。

02/28(火)

午後11時過ぎ起床。食事して半からECR144に出た。

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

Aからちょっと手間取った。先頭の文字に対応する数字を\bmod{15}で全探索すればよい。それが15の倍数の場合は最初のFを含めないケースも忘れず試す。実装上はありうる文字列をすべて前計算してから判定した。配列の長さを間違えていたがサンプルでREが出たのでペナにはならなかった。

Bは先頭または末尾の文字が一致しているか、連続する2文字で共通のものが存在すればよい。逆にそれ以外のケースは答えがない。どんなテンプレートも英子文字の前後は必ず*になるしかないので、必ず*の数が英小文字より多いとわかる。

CはSに含まれる数を昇順に並べたときどの数も一つ前の数の倍数であることが必要十分条件だから、サイズを最も大きくしようとしたらl,2l,2^2l,\dotsを入れるのがよい。つまり2^kl\le rを満たす最大のkについて、答えの一つ目はk+1とわかる。

この係数、つまり最大の要素を最小の要素で割ったときの値は、2^kに限らず素因数を重複を込めてk個持つ数であればなんでもよい。複数種類の素因数があれば並べ方も区別されることに注意。よって答えの二つ目は、ありうるすべての「最小の要素」sに対してr/s以下で使える係数それぞれの並べ方を足し上げると求まる。k\lt 20なのですべてのkに対して前計算ができて、商列挙でO(\sqrt r)

以上のことを実装して実際通ったが、コンテスト後にもっと高速になることを知った。そもそも考えるべき係数は2^kまたは3\cdot 2^{k-1}しかない。それ以外だともっと大きな2^{k+1}が使えるようになるからだ。よってこの二つをそれぞれ試せば答えが求まる。その値は十分小さいので、998244353で割ったあまりを求める必要すらない。

Dはいったんすべての値からxを引いておいて、どこに2xを足すか考える。x\ge 0なら選んだ区間に含まれるように、x\lt 0なら含まれないように選びたい。例えば前者のケースだと、長さk以上の区間は累積和を見ながら計算し、長さk未満の区間O(nk)個は全探索すればよい。後者もほぼ同様。配列外参照で1WA。

Eはrを決めれば下から順に子のうち一番同じ色の頂点数が少ないものと同じ色を塗っていくべきだから、これを全方位木dpにすればよい。1WAしたが根を変えてサンプルを試すと答えがずれていて、それを直したら通った。

うっかり答えを二分探索してしまい、木dp中に子をソートしているのも合わせて\logが二つ付き1980msとギリギリだった。1回の全方位木dpで直接答えを求められるし、ソートを使った部分も値の小さいほうから2件を知りたいだけだから、全体で線形時間にすらなる。

Fは解けなかった。nの桁数とbを全探索すると、naが分母分子に現れる分数で表すことができる。nの桁数からaの候補が絞れて、あとはその分数が本当に整数になるかチェックすればよいことになった。しかし分子だけならともかく分母にまで変数があってどうにも高速化できない。aの候補はかなり多く全探索もできなかった。

5完13位。Fはコンテスト中は0ACだった。Rubikunさんが終了直後に通していてすごい。埋め込みらしいがどこを埋め込めるのか分からない。

しばらくYouTubeを眺めた後日記を書いた。午前6時頃切り上げてラノベをしばらく読み、午前7時半就寝。

03/01(水)

午後2時過ぎに目を覚ました。眠気が残っているのだからすぐ二度寝に入ればいいものを、うっかりスマホを触ってしまい目が冴えて眠れなくなった。そのまま4時間ほどかけてカクヨムを1作読了。

kakuyomu.jp

「凡人転生の努力無双〜赤ちゃんの頃から努力してたらいつのまにか日本の未来を背負ってました〜」。設定は好みだしキャラ達の配置も良い。幼少期の時点で面白かったがやはり主人公の行動範囲が狭かったりするので、成長してからはもっと楽しみ。

布団から出て2月の読書記録をツイートした。意識的に本を読んでいた日も数日あったが、油断するとすぐスマホで楽に読めるネット小説にのめり込んでしまう。じゃあこれからは電子書籍を買えばいい、とはならない。自分の中では物理書籍を本棚に並べることが最優先されているからだ。それが既読か未読かというのは、そこまで重要な点ではない。

TLで知った競プロキャンプに登録した。CFのレートが2200以上だと無料で参加できると書いてあった。チームを組んでいないが、登録時に何も聞かれなかったのでどうなっているか謎。ソロでも5h頑張るつもりとは言え、書いてある通りPetrozavodsk Campのミラーなら難しすぎて手も足も出ない恐れがある。

Hello Muscat 2023 - Codeforces

午後7時半ごろ外出。ドラッグストアに寄ったり油そばを食べたりした後ゲーセンで閉店まで遊んだ。今日は理論値三つに加え14+の「HERA」でSSSを出した。通常解禁されたばかりの新曲なので別に苦労はしていないが、縦連が思ったより押せなくてひたすら擦ったら首筋の筋肉を痛めてしまった。

最後の方は15の「Trrricksters!!」を詰めていた。終盤ボロボロだったのがだんだん改善されてきた。家で少し座学してもう一回挑戦したら出そうだと考えている。

平日ボーナスのデュエルクリティカル率UPの影響が大きかったようで、結構な回数クリティカルが出て15クレ程度しか遊んでいないのにチュウニズムデュエルが90万ダメージ進んだ。あと5クレもプレイすれば終わるだろう。今回は開催期間の終了直前に焦る必要がなさそうで良かった。

ドンキで菓子パンやカロリーメイトを買い込んで日付が変わったあとに帰宅。シャワーを浴びてからラノベをしばらく読んでいたが、眠気に耐えきれなくなって就寝。午前3時だった。

03/02(木)

午前8時過ぎに目を覚まし、昨日読み止しにしたラノベの残りを1時間ほどかけて読了。「世界で一番『可愛い』雨宮さん、二番目は俺。」。

そう言えばこんな話だったなあ、と思い出しながら読んでいた。やはり設定が好み。口絵になっているhikariがチャラ男をやり込めるシーンも良かった。今はなろうの更新が再開され、四章が進行している。まだ読んでいない。続刊してくれれば2巻に収録されるだろうから、せっかくなのでそちらを待ちたい。

「世界で一番『可愛い』雨宮さん、二番目は俺。」。結構前にアイドルとかモデル、芸能人というキーワードでなろうを漁っていた時に読んだ作品で、結構好みだったという記憶がある。最後の更新から1年以上経過してほぼ忘れ去っていたところ、いきなり書籍化を知らされてびっくりした。

週記(2023/01/16-2023/01/22) - kotatsugameの日記

別のラノベに手を出した。午後1時過ぎに「異能学園の最強は平穏に潜む」を読了。

「よう実」を彷彿とさせる学園の設定だったり、潜むと言いつつ1巻から大胆に動いていたりと大丈夫かと思ったが、かなり面白かった。そもそも後者については本当に潜まれると面白くならない。主人公が活躍するシーンが結構あって只者でないことは十分に伝わった。しかし何者であるかはまだ隠されていて、続きが楽しみである。

学食で昼食を摂った。カツカレー。3月に入り春休み期間でミールカードが使えないのに会計時に気づいた。1日あたりの金額を使い切ろうとしなくていいのなら、わざわざカレーにカツを乗せる必要はなかった。

ラノベを受け取ってからサークルメンバーと合流し、3時間ほどTUPCの準備をしていた。当日の飲み物としてお茶や水の500mLペットボトルを48本買い、段ボールに詰めてひいこら部室に運んでから名札を作成した。

午後5時帰宅。布団に倒れ込んですぐ寝たらしい。午後11時に目覚ましで起きて半からCF #855 div.3に出た。

Dashboard - Codeforces Round 855 (Div. 3) - Codeforces

Aは大文字小文字を揃えたあと連続する同じ文字を圧縮してから判定するのが書きやすい。Bは最初の段階で貪欲にペアを作ったあと、残った大文字2個または小文字2個のペアを一つ答えに含めるのに操作が1回必要になると考える。

C1は制約からなにかdpできるんだろうなと考えつつ、解けたとしても実装が面倒で時間を消費するだけだと思ったので最初からC2を解いた。まず全部のボーナスカードを山札に積んでシミュレートし、最後に何枚か余ったら、代わりにどれを捨てるのが最適か考える。

1枚捨てるとそれ以降の山札の枚数が一様にデクリメントされるから、それで枚数が負にならない範囲のカードを捨てることができる。つまり右からの累積MINが1以上の範囲から1枚、2以上の範囲からさらに1枚、……と選ぶことになるので、選べるカードを優先度付きキューに詰めて貪欲に取ればよい。

Dはギャグ。i文字目から2文字取るのとj文字目から2文字取るので得られる文字列が一致しているとしてどこの文字が一致するか考えることで、重複チェックの際は|i-j|=1のケースしか考えなくていいことがわかる。

E1は謎。k=3なので例えば左端の文字を経由して左から4文字目と5文字目がswapできる。最初はこのような隣接する文字のswapだけを考えていたがそんな必要はなく、swapできるペアをグラフにして連結成分を考えればよい。グラフはE2でも陽に構築できる。k=3の何が嬉しいのか分からなかった。

Fは文字列ごとに奇数回出現する文字種をbitで持つと文字列連結がXORで表現できる。このXORを26bit中25bitが立った数として26通り全探索すると、片方の文字列を固定したときにもう片方の文字列の候補が絞れる。この時点で条件の四つ目は満たされているので、あとは三つ目を判定すればよい。

25種類の文字が出現することは分かっているので、残る1文字が出現しない文字列だけ考えれば良いことになる。片方の文字列を固定してから出現しない文字を全部試すと候補のカウントがメモリ制限内で行えなかったが、逆にすれば良い。

Gは木のmirror imageなる謎の用語が出現しているが雰囲気で読める。mirrorを忘れ、単に根付き木として同型であると思ってよい。つまりある部分木がsymmetricalである条件は、その子を根とする部分木たちが同型なもののペアに分割できるか、あるいはsymmetricalな1個だけが余るということになる。根付き木の同型判定はAHUアルゴリズムで計算した。

1時間弱でノーペナ全完、open hacking phaseで上の方から数人落ちて12位。調子が良かったつもりだが順位は思ったより良くなかった。CとEで時間がかかっているらしい。Eはギャグにすぐ気づけなかったのが悪い。Cはなんと山札を優先度付きキューにしてシミュレートすれば答えが求まるようだ。

今日も動画を撮っていた。コンテスト中に非公開状態でアップロードし、チャプター分けまで済ませておいて、コンテスト終了後すぐに公開した。

www.youtube.com

午前9時まで日記を書いたあとTUPCのテスター作業をした。問題文・解説の校閲。いつかやろうと思っているうちに本番が明後日に迫っていた。改めて読み直し、いくつか気になる点を指摘。こんな直前になってしまい申し訳ないとは思っている。

午後1時就寝。

03/03(金)

午後8時起床。TUPCの校閲を続けていた。日付が変わる前になんとか一通り読み終えて指摘を送った。ほとんどはすぐに修正されたが一部は明日の朝に対応される予定。ただそうして残っているのは軽微なものだけなので、ほぼ問題ない状態に仕上がっているはず。その後入力に余計な文字、空白や改行が入っていないかをチェックした。

以上のことが午前1時前には完了し、それからSRM845に出た。

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

Easyは2パターンのcheckerboardのうちどちらが近いかを決め打つと、RCマスのうち食い違っているDマスを選ぶごとに一つのbitmapが得られる。D\lt RC-Dならこうして得られたbitmapは重複せず、距離も確かにDになっているから答えは2\binom{RC}{D}D=RC-Dならどのbitmapも2回ずつ数えられるので\binom{RC}{D}D\gt RC-Dなら距離Dでないので0通りとなる。

Medはつまらない問題。値とインデックスのペアでソートしておくと、タイプ0のフェーズでは左端の、タイプ1では右端の要素を取り出して端に寄せることになる。もともとどこにあったかがわかり、そこから左あるいは右に残っている要素数がswap回数となって、BITで更新・取得が行える。こんな問題は読解が終了した瞬間に解けているはずなのに、SRM特有の入出力に余計な手間をかけさせられて腹が立つ。

Hardは解けなかった。約数だのなんだのとややこしく見えて、結局素因数の個数を見てニムをしているのと変わらないから、normal playについてはいつものXORで判定可能。値から個数への変換も区間篩で前計算できる。しかしmisere playがわからなかった。負けの状態のXORが1だからそれで判定できると思ったが全然ダメだった。

コーディングフェーズ終了間際にメモ化再帰で答えるコードを提出したが、当然間に合うわけはない。しかしチャレンジフェーズでは落とされなかった。終了直後のチャット欄で、自分のHardを落とそうとしたらエラーが出たと言われていた。再帰が深すぎるとかメモが多すぎるとかでジャッジごと変な落ち方をしたのだろうか。謎である。

ちゃんとシステスで落ちて17位、2897→2830(-67)。Hardは「misere nim」とまんまの単語で検索したら日本語の記事が出てきて愕然。こんな問題にほぼ自明なEとMをくっつけてdiv.1にするのは正気を疑う。いやもうSRMに問題の質は一切期待していないけれども。

Game Theory (HackerRank) : Misère Nim - 4bitにっき

さらなるTUPCのテスター作業としてRubyで数問解いてみた。当然ながら特に問題はなさそう。数問で切り上げ、シャワーを浴びて少し日記を書き午前6時就寝。

03/04(土)

午前9時前に目を覚ました。スマホを触らないようにして二度寝を試みたが、どうにも目が冴えている。しばらく転がっていても意識がはっきりしていくばかりだったので、結局は諦めてスマホを触っていた。

午前10時半くらいになってようやく布団から脱出。準備してコンビニで朝ご飯を買いつつ大学に向かった。今日はいよいよTUPC本番である。ここから解散するまでのことは参加記に書く。

ここにリンクを貼る

午後8時過ぎに解散してコンビニで食べ物を買い込み帰宅。買ってきたおにぎりを食べて録画の準備をし、午後9時からABC292に出た。

AtCoder Beginner Contest 292 - AtCoder

Aは問題名から内容がエスパーできたので、開いて一瞬確認したら即座にVimのコードを書いて提出。ジャッジ待ちの間に制約を読んで大文字が入力されないことを確認した。無事AC。僅差でFAだった。

Bは単にカウントするだけ。レッドカードをイエローカード2枚分として処理した。Cは1\dots Nの各整数を2数の積に分解する方法を全体O(N\log N)で数え、組み合わせた。DはUF。

Eはxからyへのパスがあるなら\rightarrow yの有向辺も存在しなければならない。そのような(x,y)を数え、最初からある辺の分Mを引いた。

Fは二分探索。判定は正三角形の一つの頂点を長方形の角に固定し、長さBの辺からどれだけ傾いているかのパラメータ\theta\in[0,\pi/6]を考えて行った。

一辺の長さをxとするとx\cos\theta\le Bかつx\cos(\pi/6-\theta)\le Aが条件。前者をギリギリ満たす\theta=\arccos(\min(B/r,1))を取って、値の範囲と後者をチェックすればよい。サンプルが弱くて怖かったが一発で通った。

Gはdp。i桁目以降だけ見たときS_l\lt\dots\lt S_{r-1}となるような?の決め方を数え上げる。i桁目を決めて、そこで大小関係が確定しなかった区間i+1桁目以降に関するdpから取得する。

i桁目の決め方については別にdpを行った。どの数字がどの区間で使われるかという遷移になって、O(\sigma(r-l)^2)で計算できる。ここで\sigma=10は数字の種類数である。全体O(\sigma N^4M)だが定数倍がかなり軽い。

ExはパフォーマンスからB引いた値の累積和が最初に0以上になるタイミングが求まればよい。累積和の累積MAXはセグ木で管理できるので、その上で二分探索する。単に累積和だけ管理していて1WA、0より大になるタイミングを求めていてさらに1WA。後者についてはサンプルすら合っていないことに2ペナ出すまで気付かなかった。

43分半と2ペナで全完、11位。Exのしょうもないミスが残念。振り返りをしてもなおコンテスト時間が余ったので、録画を続けたままTUPCに関しても話していた。撮り終えてすぐ投稿。

www.youtube.com

コードゴルフ。AはやはりVim。BはAWK。CもAWKでこちらは負け。FはRubyで二分探索していたが、答えを直接求めるコードにボロ負け。他は手付かず。

今日は午前3時からUniversal Cupに参加する予定。すでに眠いため、日付が変わったくらいに布団に倒れこんで仮眠に入った。

午前2時過ぎに目を覚ました。非常に眠い。時間的にはあと30分ほど眠っていられるが、そうやってギリギリを攻めるともしかしたら寝過ごしてしまうかもしれないほどの眠気だったため、そのまま起きていることにした。時間をかけてじっくり布団から這い出しUniversal Cup 6回目。今日はTaiwanセットだった。

2022-2023 ICPC Asia Pacific - Taoyuan Regional Contest - Dashboard - Contest - QOJ.ac

チームでMAGCBDJIFHLを解き、11完13位。自分はABJFLを担当した。質の悪いセットだと感じたが順位が良かったのでそこまで嫌いにはなれない。

最初、順位表に従ってMAGCがポンポンと通された。MとCがぷらさん、Gがかっつさん。この4問は明確に簡単枠だった。自分が担当したAはそれに加え不快な要素もあった。コドンからアミノ酸への対応表が問題文に与えられているので、それに従って入力のRNAを翻訳せよという問題。場合分けのコードをプログラムで生成した。

次にBを通した。ladder部分は簡単で、四角形のグラフで下の2頂点が彩色されている場合に上の2頂点を彩色する方法が(\lambda-2)^2+(\lambda-1)通りあるので、これを(n-1)\cdot k乗すればよい。

真ん中のk角形の部分は、ある固定した頂点に色1を塗るとして、そこからぐるっと一周しつつ「色1を塗る場合の数」「色1以外を塗る場合の数」を計算し、最初固定した頂点に戻ってきたときの前者の値を\lambda倍すると求まる。一周する部分は連立漸化式になるが、解くのが面倒だったので行列累乗で計算した。

次にDが通されていたのでぷらさんと一緒に読んでいたのだが、まったく問題が理解できなかった。問題文では図を含め丸々2ページに渡って暗号通貨の説明がされているようで、どこが問題になっているのかが把握できない。そのうちぷらさんに「自分がこれをやるので別の問題に進んでください」と言われたので、ありがたく押し付けることにした。自分が離れてからしばらくしてついに読解に成功したらしく、解法自体はやるだけですぐ通っていた。

自分はJに進んでDの後に通した。切り開いたサイクルとパスをそれぞれ別で管理し、辺の使用可不可をセグ木で、コストを累積和で取得した。最短距離を求めるクエリでは指定された頂点がサイクルの上にあるか辺の上にあるか考え、各パターンでどのような経路が最短になり得るかを列挙してそれぞれ長さを求めた。列挙が足りているか心配だったが一発で通って安堵。

かっつさんによってIが通されるのを眺めつつFを考えていた。両端はとりあえず1が確定する。その両端からそれぞれ確定している範囲でオイラーツアーを辿ることで、根から現在いる頂点までのパスを管理することができる。確定している範囲を全部見終えたとき、その二つのパスは根からある位置までは一致しているはずで、その間を繋ぐ未確定の部分では、左から作ったパスに沿って一致している一番下の頂点まで登った後、右から作ったパスに沿って降りていくことになる。

そのような登って降りての間にこれまでに使っていない頂点たちを子としてくっつけると全体のオイラーツアーとなる。ここは貪欲にやればよい。子として頂点番号が最小のものをくっつけるか、一つ上ったり右から作ったパスに沿って降りたりするという二通りしかないので、辞書順最小になるように選ぶ。特に後者について丁寧に考えながら実装したら一発で通った。

Hはランダムに生成された点列のすべての連続部分列に対してそれぞれ最小包含円を求める必要があるらしい。検索するとn点の最小包含円を求めるのがO(n)になるようだ。ランダムな順で点を追加して、これまでの最小包含円に入らなければ更新するというもの。今は点自体がランダムなので追加を順番に行うだけでよく、連続部分列の始点を決めるごとにO(n)ですべての終点に対する答えが求まる。

最小包含円 | libalgo

この段階で解けたと勘違いし自分はLに移ったが、まだ解けていなかったようだ。その後ぷらさんにより無事通された。Lは特殊なプログラミング言語のコードを書くタイプの問題で、そういうものが大好物な自分としては存在を知ったときから気になっていた。しかし読んでみるとほとんどBrainfuckで拍子抜け。メモリが-1から9までの値しか取らないことと、実行を停止する命令が追加されていることが変更点。

問題は、k=1\dots 6が入力で与えられるので、非負整数を読み込んでそれがkの倍数かどうか判定するプログラムを出力せよというもの。読み込むというのは十進表現を1桁ずつだから、0から9の数に対して適当な操作、例えば\bmod 3だったりができればほぼ十分。そしてそういうコードをBrainfuckで書いたことがある。

条件分岐がwhileしかないのでそれを使う。例えば数xが0から3の範囲にあるとして、0で初期化されたans\bmod 3した値を代入するコードは次のように書ける。

while(x){x--;ans++;while(x){x--;ans++;while(x){x--;ans-=2;}}}

3重のこのコードを9重にすれば9まで対応できる。同様の方法でいろいろな条件分岐を実現し、kの値に応じて6通りのコードを手作業で作成した。デバッグ機能付きのチェッカーが配布されていたのでかなりスムーズに正しく動作するようになって、提出したら通った。

後からよく問題文を確認するとサンプルにk=1,2,3,6の場合の答えがあって愕然。こういう問題のサンプルは実際には使えないプログラムになっていることが多く、はなから当てにしていなかった。

1時間20分残して残りはEとK問題。EはTL 30secだしかなり大変そうなフローの雰囲気があった。一方Kはグラフに言い換えると考えやすそうな形になったので、そちらに注力した。ぷらさんは自分と一緒にKに、かっつさんはEに取り組んだ。

Kは連結成分ごとに解いてよい。辺を偶数本持つならtype Aだけで取り尽くせると分かった。この時の証明は正しくなかったが、結論自体はEven Degreesを考えると正しい。さらにtype Bまたはtype Cは使うならどちらか片方を一つだけということも分かっていた。なのでグラフからtype Bまたはtype Cの辺を一組取り除いた後の各連結成分が辺を偶数本持つか判定できれば良いことになって、できなかった。Eも実装に移れるほどの進展はなかったようでそのまま終了。

感想戦。最初4問はどれも本当にしょうもない問題ばかりだったが、しょうもないだけまだマシ。自分が読解を諦めたDは、頂点に重みがある出次数高々2のDAGが与えられて、全頂点に対し自分に到達可能な頂点の重みの和を求める問題だったらしい。愚直が通る。問題を解くのに関係ない説明がひたすら続いていた問題文が最悪だった。元ネタが暗号通貨だからと言ってそれについて説明する必要はない。

Iは二部マッチングで、怪しげな制約から辺の本数が十分少なかったらしい。問題文や図がいかついのでやってもらえて助かる。

Hは点列を連続部分列K個に分割し、それぞれの最小包含円の半径を求めて総和を最小化する問題だった。半径が全部求まっても、分割する部分が普通にdpするとO(N^2K)なのでまだ解けていなかったということ。結局枝刈りしたら爆速だったらしい。

TLの言及で、最小包含円の半径が同じならそのうち極大なものだけで遷移するとよいと知った。自分で実装してみたら、ユークリッド距離を真面目に計算したせいで距離の比較で毎回sqrtを使うことになり、全然高速にならず苦労した。2乗の状態で持っておくと一気に爆速になってびっくり。自分の幾何ライブラリで距離を比較している部分も、EPS周りが少し怖いがそう書き直しておくべきかもしれない。

水曜日にレジったキャンプ「Hello Muscat 2023」だがコンテスト中にメールが届いていて、これからチームを組めるようだ。せっかくなので今Universal Cupに出ているこのチームで組もうと誘った。全員OKだったのでひとまず各自での登録をお願いし、解散。

キャンプに本格的に参加することになったので期間中の予定を確認。日本時間で午後3時から午後8時までがコンテスト時間らしい。インターン先の定例会は欠席させてもらうことにした。セミナーはたまたま休みだった。1on1は予定をずらしてもらった。

それからずっと日記を書いていた。午後5時就寝。

03/05(日)

消えた。

週記(2023/02/20-2023/02/26)

02/20(月)

午後4時半前に起床しインターン先の定例会に参加した。

1on1で認証回りを頑張ったのとバグ修正のチェックが先週の進捗。今週は認証を突破できたのでそれも含めコードの手直しをするタスクが振られている。

勉強会はマネジメントの話だった。昨年最終回の続き。何かを行う際、目標から決めていくトップダウン型とできることからやっていくボトムアップ型の対比が印象的だった。バランスが大事ではあるが、トップダウンで目標を意識する重要性が説かれることが多いのも事実。これには人間の傾向としてボトムアップ型に偏りがちということがあるのではないだろうか。少なくとも自分はそうだった。

インターンを初めてしばらくしたくらいに受けた助言で「実現できるかどうかではなく実現したら嬉しいことに取り組みましょう」というものがあった。これもトップダウン的な話である。結構感銘を受けていまだに覚えているが、自分でそのようにできているとはまだまだ思えない。

発表と質疑応答が終わったのは午後8時だった。最近この時間まで続くことが多い。別に苦痛なわけではなく、むしろかなり楽しく参加している。それから先週の週記を書き上げ、午後11時に投稿した。

ABC-EFの最短コードを読んだ。Eは\min(i,N-j+1)が面倒。数列の両側からインデックスを交互に見ることで\minの値を固定し、まだ見ていないインデックスで同じ値を持つものを数えることで係数を求めることができるようだ。

Fは答え\frac{(N^2-3)(2N-4)!}{(N-1)!(N-2)!}について、階乗をチマチマ前計算するよりa_N=\frac{(2N-4)!}{(N-1)!(N-2)!}とおいてa_{N+1}=\frac{(2N-2)!}{N!(N-1)!}=\frac{(2N-2)(2N-3)}{N(N-1)}a_N=\frac{4N-6}N a_Nのように計算してしまうのが良いらしい。昨日より縮んでいた。その後係数を4-\frac 6 Nとすることでさらに縮んでいた。

少し日記を書き、午前1時からセミナー準備を開始した。先週の残りがあるので量としてはそれほど用意しないつもりだったが、それ以上に教科書の内容がうまく把握できずかなり苦労した。4時間かけて何とか4ページほどのメモを作成した。

シャワーを浴びて午前5時半就寝。

02/21(火)

午前9時45分起床。原付で山に登り、購買で朝食を確保していつものように10分遅れでセミナーの教室に到着した。

午前中は同級生の発表だった。ある定理の証明が一か所完成していないとのことで、それに関して教科書の文言を確認したところコーナーケースがあるように見えた。自分の勘違いかとも思ったが、教科書をもっと読んでいくとやはり辻褄が合わない。その後明確な誤りを発見し発表はお開きになった。定理自体に問題はないはずで、証明がよくない。

連結なグラフを閉曲面に埋め込むと、各面についてその内部の閉曲線を連続的に1点に縮めることができる。閉曲線の内外両方にグラフがあると連結ではなくなるからだ。このような性質を持つ面の内部は開2-胞体、つまり開円板と位相同型になり、面の境界は円周と位相同型になると書かれていた。しかし境界がサイクルでないような面などいくらでも考えられるから、最後の文言は明らかに誤りである。

今書いた論理の流れのどこで間違いが犯されているのかはいまいちわからない。ただ教科書の図には境界がサイクルにならないような面が書いてあるのに、その内部も開2-胞体だと強調した上で境界が円周と位相同型などと言っているのだから、間違っているのは自分の勘違いではないはず。

正午を少し過ぎたくらいに購買で昼食を買い、教室で食べて、すぐ博士課程の方の発表に入った。相変わらず定義の少し先の命題で詰まっている。そもそもこの定義というのがあまり直感的ではないから精密に見ておく必要があるのに、添え字が1違うとか上限下限にイコールが付いているか付いていないかとかの微妙な部分が毎度毎度曖昧。正直言って腹が立つ。自分で資料をチェックする気力も失せて久しい。

今日もあまり進まず午後2時半終了。30分の休憩となった。つい先ほどまでそこそこ雪が降っていたはずだが、今見ると晴れ上がっていて良かった。何とか原付で帰れそうだ。

休憩時間は机に突っ伏していた。午後3時から自分の発表。今日は2時間かけ、先週やり残した分に加え昨日準備した分まで全部発表した。昨日の部分はやはり難しい。理解はしているつもりだったので自分なりのポイントを考えながら喋っていたつもりだが、感触が悪い。似た内容を何度か繰り返したり、先生からの質問に答えたりしたので、ある程度伝わったものとは思う。

来週は大学入試の採点作業が忙しいらしくセミナーもなくなった。再来週の同級生の発表については、今日の件で教科書の信用度が落ちたため、自分が読んでいるDiestelに合流することになった。とりあえず次に控える4.4章を丸々やってもらう予定だ。

解散後、学割証の発行のため川内キャンパスに降りた。学食もそこで食べようと思ったら春休み期間で昼しか営業していなかったため、コンビニで菓子パンを大量に買い込んだ。

午後6時帰宅。2時間ほどTUPCのテスター作業をしてから布団に入り、ラノベを読んでいた。午後9時までは起きていた痕跡があるが、その後いつ寝落ちしたか定かではない。

02/22(水)

午前2時半頃目を覚ましたはず。そのままラノベを読んでいた。午前6時頃「ネトゲの嫁が人気アイドルだった」3巻を読了。

2巻を読んだのが1年以上前で内容をあまり覚えていない。この巻では新たにヒロインと同じアイドルグループに所属する義妹が登場し、主人公からは見えないアイドルとしての苦労が扱われた。その話はなかなか辛かったが、義妹は小動物的で可愛らしかったしヒロインとの交流もほんわかしていて、全体としては楽しく読むことができた。

このシリーズは1年近く新刊がないので打ち切りになってしまったのだろうと考えている。積んでいるうちに打ち切りになったシリーズを読むタイミングというのは何とも難しい。そういう情報は読む前からネガティブな影響を与えてくる。

その後も別のラノベを読んでいたが、午前9時を過ぎて布団から出た。

メールでこのブログの記事に付けられたはてなスターが合計2000に到達したことを知った。いつもいつもありがとうございます。

午後4時までTUPCのテスター作業をしていた。その間にABC287の賞品でアマギフ10000円分が届いた。以下のように当時は学生賞を逃したと思い込んでいたが、これでもギリギリ5位だったらしい。

1WA全完で19位。賞金には遠いかと思ったら上位にそれほど学生がいないようで、ペナがなければ滑り込めていたらしい。

週記(2023/01/23-2023/01/29) - kotatsugameの日記

午後4時半就寝、午後10時頃起床。またラノベを読んでいた。

集中力が切れたタイミングでTLに目をやったところ、西尾維新書き下ろし・短々編「緊急対談!戯言遣い×阿良々木暦」というのが流れてきたので開いた。短々編といってもアニメ声優による朗読形式になっていて動画時間は17分もあったが、MVも凝っているし話の内容も興味深いというか先が気になる感じで、自然と全部聴いてしまった。

www.nisioisin-anime.com

午前1時頃「ひきこもりの俺がかわいいギルドマスターに世話を焼かれまくったって別にいいだろう?」3巻を読了。相変わらずコミカルでふわふわした展開が続き気楽に読めた。クライマックスは明らかに人死にが出るような規模のクーデターだったが、それでもどこか緊張感のない描写だったのはむしろすごい。

また別のラノベに手を出した。

朝方、今後GCJが行われないことになったと知った。最近のレイオフでこれまでの担当者がいなくなったのは聞いていたが、まさかコンテスト自体がなくなってしまうとは。青天の霹靂だった。

午前5時半就寝。

02/23(木)

午後2時半起床。相変わらずラノベを読んでいた。午後6時半頃「転生したら皇帝でした」1巻を読了。

2年ほど前に読んだなろうの書籍版。1巻が出たのは1年前で、現在既に4巻まで刊行されている。内容を結構忘れていて面白かったという記憶だけが残っていたが、今読んでも変わらず面白い。真の実力を知られてはならないという緊張感が常に漂っていながらも、これはと見込んだ相手に自分の真価を見せつけて心酔させるシーンが時おり挟み込まれ、読者としてずっと我慢を強いられるわけではないのが嬉しいところ。ただこの先の展開をなろうで知っている自分としては、1巻はやはり耐える側面が強いように感じられてしまった。

布団から出てTUPCのテスター作業をした。2時間弱でまた布団に戻り、しばらくラノベを読んでいたら午後10時前に寝落ちした。

02/24(金)

午前0時半起床。布団でラノベを読んでいた。午前4時頃「転生したら皇帝でした」2巻を読了。

この巻で主人公がついに真の実力を明らかにする。なろうで読んだときはいよいよかという気持ちが強かったが、本になってみると2巻に収まってしまうくらいだったようで展開の速さに驚かされた。それでもこのカタルシスに向けた溜めは十分。クライマックスは緊張に汗を垂らしながらじっくり読んだ。やはり最高だった。

シャワーを浴びて1時間ほどインターンの進捗を産み、少し日記を書いて午前7時頃また布団に戻ってきた。ラノベを読んで午前8時半就寝。

午後1時45分に目覚ましで起床。ちょうどTLに第12回PASTの過去問が公開されたというツイートが流れてきたので、慌ててAとBだけ解いた。

第12回 アルゴリズム実技検定 過去問 - AtCoder

Aは問題文を読むのに苦労したが、答えは\min(X+Z,Y)となる。PASTのA問題はひたすら面倒という印象だったので、かなりきれいな式になってびっくり。dcで書いた。Bは何も考えず後ろ2文字を消すコードをsedで書いて1WA。N\lt 100の処理が面倒だったので、素直に100で割ることにしてRubyで出しておいた。

Cからはすぐ縮みそうになかったので切り上げ、ちょうど午後2時になったので1on1に参加した。

昨日の進捗は実はコードを少しリファクタリングしたくらいしかなく、早々に今週のタスクの説明に移った。新しい機能を一つ実装するという話だったが、導入として少しコードを書いてもらいながら説明を受けているうちにいつの間にか完成してしまったので、その周りを整備する作業だけが残った。1時間半で終了。

この後はゲーセンに行こうと思っていたが、日曜日終了のAHCにまだ1回も提出していないので、そちらに取り組むのを優先することにした。しかし仮眠によって英気を養おうと布団に横たわったところうっかりカクヨムを開いてしまい、そのまま10時間ほど読みふけっていた。2作読了。

1作目、「特級探索者、配信者となる~攻略マナーを配信してただけなのに何故かバズって困ってます~」。超強い主人公がマナー講座の動画をアップしたところ、何気なくやっていたことがあまりに凄すぎてバズるという話。設定も導入も面白かった。主人公の性格からして動画投稿にあまり乗り気でないのは自然だが、もうちょっと積極的にやってくれると目立つシーンが増えて個人的には嬉しい。

kakuyomu.jp

2作目、「推しにダンジョン産の美味いもんを食わせるために、VTuberになってみた」。これも主人公最強モノ。面白かった。話が進むごとに主人公の人間離れしている様がどんどん明かされていって良かった。際限なしの強さだ。ここまでくるとVTuber要素は別に要らない気もする。飯テロ動画をアップするのに手元しか映せないのはちょっと窮屈。

kakuyomu.jp

午前1時半に布団から脱出。水曜日の日記にGCJが終了することを書いたが、なんとTCOも今年が最後となるらしい。この最終回はすでにオンライン開催となることが確定しているそうで残念。

discussions.topcoder.com

いよいよAHCに取り掛かった。アイディア自体は先週問題を読んだときから頭の中にあったので、ひたすら実装。盤面からいくつかセルを選び、そこを掘って頑丈さを求め、それが小さい点を繋ぐというもの。

もっと具体的に言う。最初に盤面から縦横いくつかおきにセルを選んで掘って頑丈さを求め、他のセルの頑丈さを直近の選んだセルと同じ値だと推定した。次に選んだセルからグリッドグラフを作り、辺のコストをその上に乗るセルの推定した頑丈さの和で決めた。最後に、水源や家それぞれから直近の選んだセルまでの経路を掘り、グリッドグラフ上で接続する問題だと思って適当な貪欲で解いた。

最初の提出は24.5M点。これは自分の提出一覧で見られる点数を書いているので、小さくするのが目標である。とりあえず正しいコードが書けたので、手元でいくつかのケースを試しつつパラメータ調整をした。また、セルの頑丈さが推定値を上回っていた場合に追加で掘るとき、パワー100連打をやめて指数的に変化させた。以上2点の改善を行った次の提出では11.7M点になった。

そこからパラメータ調整で少しずつ点数を下げていたが、経路を連続的に掘る際にひとつ前に掘ったセルの頑丈さをパワーとして使って次のセルを掘るようにしたらそこそこ大きく下がった。10.3M点。

最後に、グリッドグラフの辺を一気に掘るとき、端点のうち使おうとしているパワーが小さいほうを掘って一つ縮めるという操作を繰り返すようにしたら10.1M点となった。先ほどの掘り方だと頑丈さの累積MAXを使っていることになって、辺の真ん中に頑丈さのピークがある場合に損していた。これを解消したつもりだ。

この時点でギリギリ400位を切ったくらいだったはず。アイディアを温めていた時間は長いのに全然うまくいかなくて残念だった。温めていたといっても別に考察していたわけではないので当然か。

提出の待ち時間などにまたカクヨムを読んでいた。午前7時頃「RDA.com ~死を恐れないRTAダンジョン探索者、現代ダンジョンにてゲームと同じ挙動を再現し、物理法則ガン無視無双~」を読了。

導入はいわゆる追放モノであまり好みではなかったが、その後は非常に面白かった。単純に主題となる最強格主人公の無双が面白いし、それにダンジョンとかタイムアタックとかバトロワとか、果てには妖怪・神話・都市伝説の要素が無理なく組み合わさって目くるめく世界観が心地よい。

kakuyomu.jp

シャワーを浴びて日記を書いていた。途中でパックご飯を食べようとしたとき、温め時間2分のところを冷凍弁当のときの手癖で7分にしてしまった結果、全体的に縮んで硬くなり、一部は噛み切れなかったため泣く泣く捨てた。この失敗は2回目。

午前11時に布団に入り、ハーメルンの更新をチェックしていたらすぐ寝落ちした。普段通りなら午後2時からのUniversal Cupに備えもっと早く寝なければならなかったのだが、今回はチームメイトがゆるふわ競プロオンサイトに参加するので日曜日午前3時からの枠で参加することになっていた。

02/25(土)

午後8時半起床。急いで食事して午後9時からARC157に出た。

AtCoder Regular Contest 157 - AtCoder

Aは|B-C|\le 1である必要がある。逆にこれが満たされていればXXXに置き換えるなどしてADを好きに揃えられるので十分……ではない!1WA。B=C=0がコーナーケースだった。

Bは結構難しい。Xの個数をcとする。c\ge KであればわざわざYXにする必要がないため、XからK個を最適に選ぶ問題となる。c\lt Kの処理で詰まっていたが、全体を1度置き換えてからN-K個をもう一度置き換えると考えれば、XN-c個となってN-c\gt N-Kが満たされ最初のケースに帰着できる。

あとはc\ge Kで解ければよい。Yが1文字もない場合は\max(K-1,0)が答え。そうでないとき、すでに存在するYの隣のXを選ぶようにすると、基本的には1文字置き換えるごとに答えが1増える。連続するXで左右にYがあるものを全部置き換えればボーナスで答えがもう1だけ増えるので、このボーナスを最大化する問題となって、置き換える必要のある文字数が少ないものから貪欲に使うとよい。

CはPのスコアを「Y同士が隣り合う箇所を2回選ぶ場合の数」と捉えることで、逆に上下・左右に隣り合うYの寄与を考える問題にする。同じ所を2回選んだ場合、それを含むPはcombinationで普通に計算できる。そうでない場合も2箇所のうち先に出現するところから後に出現するところまでをdpでまとめて計算することでPを数え上げることができる。

Dは面白かった。Yの個数をcとする。柵によって行がh分割、列がw分割されると、区画はhw個できるので2hw=cが成り立つ。この(h,w)を全探索する。柵の置き方について、例えば行に置いた柵だけ見たときはh個の区画に2w個ずつYが含まれるはずなので、上にY2w個ある位置に一つ、4w個ある位置に一つ、という風になっているとわかる。

この時点でまだ柵の置き方が確定していないのは、Yを含まない行・列をどの区画に入れるか決まっていないというだけの話だから、実のところなんでもよい。適当に選んだ置き方が正しく分割できていれば、可能な選び方すべてをまるまる答えに加算できる。(h-1)+(w-1)本の柵について置ける位置は被らないので、それぞれに対して数え掛け合わせることで足すべき場合の数が求まる。c=0で1ペナ。

Eも面白かった。Yを書き込んだ頂点について、それに隣接する頂点にはすべてXを書き込む必要があるので、親の数がBに、子の数がCに寄与する。この寄与を具体的に見ると(B,C)に対し(1,0)(1,2)(0,2)の3通りしかない。これらによってBCが達成できればA+B+C=N-1より自動的にAも達成できるので、以降Aは無視する。

3種類の寄与のうち(0,2)は根だから使うか使わないかを両方試せる。残りの頂点に隣り合わないようにYを書き込んで、対応する(1,0)または(1,2)を足し合わせて(B,C)(あるいは(B,C-2))を作ることを目指す。

各頂点がO(N^2)状態持つ木dpに見えるが、片方を使う回数を固定したときもう片方が最大何回使えるかさえ求まれば判定は可能。例えば(1,0)を使う回数を固定すると、これは葉にYを書き込んだ回数だから、各ノードではそれ以下にある葉の数だけしかdpを計算しなくてよく、全体で2乗の木dpになる。遷移のミスで1WA。

Fは解けなかった。共通部分列なので「Sの何文字目とTの何文字目がマッチ」のような遷移のdpを書きたくなるが、文字の入れ替えで困る。そこでSTを1文字ずつ同時に見つつ、それぞれ共通部分列の何文字目まで取ったかを管理する方針を考えた。

当然STで取り出せた文字数には偏りが生じるから、長いほうがどちらか・長さにどれだけ差があるか・もう片方からまだ取り出されていない文字列は何かを状態に持つ必要がある。この差というのは普通に考えればN/2まで到達しうるが、実は最適解はもっと小さくなるのではないかと思った。

どんな値になるかわからないまま適当に上限を定めてdpを書き始め、長さに関しては正しい答えが出せるようになったが、復元が複雑すぎた。どうしようもないままコンテスト終了。

5完7位。なかなか全完できない。Fは考察の道筋が全くできていなかったが、差が十分小さいというのは合っていたらしい。しかしこの「十分」というのはギリギリdpできるくらいという意味なので、復元は文字列を一緒に持つなどせず真面目にやらないと間に合わなそうだった。

今日も動画を撮っていた。コンテスト終了後念入りに各問題の振り返りをするところまで録画し、すぐYouTubeにアップした。

www.youtube.com

実は今日はCFでコンテストがあったらしい。完全に見逃していた。気づいたのは午前0時頃でExtra Registrationすら終了していたが、問題は読んで解けるところまで解いておいた。CF #853 div.2。

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

Aは先頭2項の\gcdが2以下である必要があって、逆にこれさえ満たしていれば残りはどうでもいい。先頭2項を全探索する。

Bはsを真ん中から二つ折りにし、重なった文字が異なる位置を考える。どんな操作も、この重なった文字の一致・不一致をある区間でflipすることになるから、異なる位置がちゃんと一つの区間になっているかチェックすればよい。sが最初から回文でもよい。

Cは数列ごとに値がdistinctなので、A_iA_jを連結した数列の要素の種類数は2nからA_iA_jに共通して現れる要素の種類数を引けば求まる。これを分解すると、まず2nm(m+1)/2回答えに足され、1\le v\le n+mに対しvが出現する数列の個数をc_vとして答えからc_v(c_v-1)/2引くということになる。

数列のインデックスごとにクエリによる値の変化を記録することで「インデックスiA_lからA_{r-1}まで値v」という情報が合計n+m個得られるので、それぞれについてc_v\leftarrow c_v+(r-l)とすることでcが求まり、答えが計算できる。

Dは面倒だった。k=0が許されていないので、操作によってa\ne 0の状態からa=0にすることはできない。逆も当然できない。このケースを処理すると、abはそれぞれ少なくとも1bitずつ立っている状態になる。その右端の位置が揃っているとしたら、そのbitを使って左にあるbitを右から順に合わせていくことができる。1bit合わせるのに高々1回の操作が必要。

なので問題は右端をどう揃えるか。aの右端がbより左にあれば、1回適当な右シフトをXORすることで揃えられる。右にある場合は、まずbの右端と同じ位置のbitを立て、その後aの「左端の」bitを使ってbの右端より右にあるbitを消していくことで揃えられる。

右端を合わせる前も後も、どちらも1回の操作で1bitずつ揃えていると思えるから、操作回数は明らかにn回以下となる。シフトの左右と符号の対応がうまく認識できず、混乱しながら実装した。

E。s_ns_n-1の商列挙で、\lfloor s_n/x\rfloor=a\lceil s_n/x\rceil=bとなるようなx区間O(\sqrt{s_n})個に分解する。この後はpa+qbという形で表せるs_iをそこそこ高速に数えられればよい。pqが負になれないので単に\gcd(a,b)の倍数が全部作れるというわけではなく、b=aまたはb=a+1となることを利用して頑張る必要がある。

b=aの場合は簡単で、aの倍数を数えればよい。aの倍数を全部見てsに存在するかチェックするという方法でも、全体でs_nの約数の総和と同じ回数しかループが回らないので十分高速。あるいは調和級数O(s_n\log s_n)と思ってもよい。

b=a+1の場合、s_iは[tex:a2]以上であるか、ある1\le k\lt aについて区間[ak,bk]に含まれている。kを全探索しあらかじめ求めておいた累積和でカウントするとO(a)だが、こちらは今度こそ調和級数による評価ができて、全体でO(s_n\log s_n)となる。

Fは解けず。T'が4文字以下のケースは全探索して、5文字以上はk素数として全探索することを考えたが、後者がどうやってできるのかわからなかった。コンテストに最初から参加していたとしても解けたとはあまり思えない。

システス後にAからEまでのコードを提出したら全部一発で通った。

ARC-Aのコードゴルフをした。dcで頑張る。|B-C|\le 1についてはスタックにNoYesが積まれた状態でB-Cを使ってRを行うことでうまく判定できた。B-C\le -2なら先頭の要素が後ろに、B-C\ge 2なら後ろの要素が先頭にrotateされてくる。B+C=0のチェックはB-2C=0でも通った。これは単純なテストケースハック。

午前3時からUniversal Cup 5回目。今日はOsijekセットだった。先週に引き続きほとんどの問題文が短くて読みやすかった。

The 1st Universal Cup. Stage 5: Osijek - Dashboard - Contest - QOJ.ac

チームでIFGJAを解き5完41位。自分はすべての問題に関わった。

最初にIが解かれた。ぷらさんが読みに行ったが微妙に詰まっているようだったので自分も一瞬読みに行き、操作が数列のreverseとrotateになっていることを指摘した。これによりほとんどのケースで2nが答えになるとわかる。小さいケース、具体的にはn\le 2に注意してほしいというところまで伝え実装は任せた。しかし自分もぷらさんもn=2の時の答えが2になると思い込んでおり、二人で確認してから提出したのにWA。実際は1であった。

ここからしばらく何も解けない時間が続いた。自分はDに、ぷらさんはFに、かっつさんはGに取り組んでいたはず。解けずに唸っているとFからHELPが来て、読んで喋っていたら解けた。

出現する文字の種類数を\sigmaとする。真ん中を固定し、左右2文字ずつについてどんなものがどれだけ出現するかを数えたい。一方は真ん中をずらしながらdpできて、更新がO(\sigma)箇所なのでTLにも収まる。しかしもう一方はdpを戻しながら計算する必要があり、単純に書き換えたO(\sigma)箇所を保存するとメモリが足りなくなった。ここで、実はその時点のdp配列から直接計算できるのに気付いた。

答えを計算する際は左のdp配列と右のdp配列の各点積のようなものが必要になるが、dp配列を更新しながらこの値も差分更新することで同様にO(\sigma)で計算できる。実装はぷらさんに任せた。

Gも捗っていないようだったので、かっつさんと喋りながら手でいろいろ試していた。n=3で壁8枚を達成した後、n=4n=5を適当に作っているうち、外周を全部埋めてn-2のケースに帰着するのが最適じゃないかと思い始めた。

外周に限界まで壁を作ると2n枚置けるが、このとき外周に接する辺はもう使えない。よって外側1マスを無視して考えることができ、n-2に帰着できるというわけ。nが3以上の奇数なら最後3\times 3だけ手作業で埋める。別のアイディアがあるわけでもなかったので試しに提出してみたら通った。実装は自分。

次は全員でJと格闘していた。n=2,3,4が不可能なことは手で確認できて、そのままペンシルパズルを進めているとn=5,6,7,8が構成された。しかしそれらからは規則性が見つからない。このまま続けていてもキリがないと感じたので、小さいnを考えるのではなく一般に適用できるパターンを探し始めた。

すると、9\times 9マスにおいて左上からスタートして右下でゴールするような手順が見つかった。この手順はいくらでも延長できるので、nn=9+8kという形をしていれば対応できる。よってn\bmod 8で分類し、それぞれこれまでに見つけた盤面と組み合わせて作れないかを探ろうとした。

これはうまくいかなかったが、7\times 7でも同様の手順が構築され、n\bmod 6で分類したら見事全通り作ることができた。7\times 7の手順で最後に踏むマスを取り除くと6\times 6にできるというのがポイントだった。実装はかっつさんに任せ、ぷらさんはDに、自分はAに行った。

Aは最初に読んだときは直接木dpすることを考えていて解けなかったが、bitごとに考えればすぐわかった。つまり、例えばANDなら0\le i,j\lt 25に対してvibit目とjbit目が立っている頂点だけを使うパスを数え、2^{i+j}を掛けて答えに足すと求まる。ORはほぼ同様で、XORもi,jが固定されていれば22状態の木dpで求められる。

Jが通るのを待って書き、提出。しかしTLEした。どこが遅いのかわからない。パスを数えるのにUFを使っていて、もしかしてこのO(\alpha(N))が効いているのかと思いdfsに書き直すもまだTLE。いくつか定数倍高速化してもずっと通らない。最終的に、最初に頂点番号をdfs順に振り直し、以降のdfsはforループで処理できるようにしたら通った。

確かに自分の解法ではO(N)頂点のdfsを延べ975回行っているから、再帰呼び出しのオーバーヘッドも無視できない回数嵩んでいるようだ。確か手元のパスグラフだと1.6secから0.8secとほぼ倍速になったはず。それにしてもこういう定数倍高速化を問う問題は初めて見た気がする。

残り40分でDを考えていた。ランレングス圧縮した後のdpを多項式で表現すると、あるブロックを計算するときはその二つ前までのブロックに対応する多項式さえ分かればよいことになった。ここから、最初の2ブロックをfgとしてその先を多項式cdによってcf+dgという形で表現し、適切なタイミングで(f,g)を取り直すという方針が立った。ABC281-Exでも用いた方法。しかし実装は間に合わなかった。

Editorial - AtCoder Beginner Contest 281

感想戦。今日は全員で取り組んだ問題が多かったので、改めて話すことは少なかった。Aも自分がTLEに苦しんでいる間に全員問題概要とコードを把握していた。そういえばこれは他参加者のツイートを読んで気づいたことだが、頂点番号の振り直しはdfs順ではなくbfs順のほうが良かったらしい。木dpで子を舐めるときのアクセスがシーケンシャルになる。

問題の振り返りもそこそこに雑談に移行し、ゆるふわ競プロオンサイトの問題について話したりしていた。

https://www.hackerrank.com/yfkpo4

午前9時半に解散。それからしばらく格闘してDを通した。基本的には上で書いた方針だが、(f,g)を具体的に計算するのを止めた。

もっと具体的に書く。答えを求めるために、各ブロックに対応する多項式の総和を計算していた。これは当然(f,g)によって表現できないので、最近のブロックの値だけそのように表現しておいて(f,g)を取り直すタイミングで具体的な多項式を計算し足すということをしていた。このために(f,g)の具体的な値を知る必要があった。

しかし現在の(f,g)による表現が分かっていれば、(f,g)を取り直す際の変換行列を使って一つ前の(f,g)による表現が計算できる。この状態だと一つ前で答えに足したかった多項式とそのまま足し合わせられるので、同様にして最初まで遡っていくことで途中の(f,g)を計算することなく答えの多項式が求められる。これでTLEが取れた。

実のところ、答えとして計算した多項式のうち必要なのはx^kの係数のみなので、毎回直接計算すれば十分高速らしい。後から提出してみたら通ってしまった。

午後3時頃まで日記を書き、就寝。

02/26(日)

午後8時起床。AHC018が終了していた。結局金曜日以降は何一つ取り組まなかった。

KoP 4thのチュウニズム部門決勝まで終了していたので、ライブ配信を巻き戻して決勝戦と他いくつかを眺めていた。

www.youtube.com

午後8時半に布団から脱出し、食事して午後9時からABC291。

AtCoder Beginner Contest 291(Sponsored by TOYOTA SYSTEMS) - AtCoder

AはRubyで、正規表現によるマッチングがマッチした位置を返すことを用いて解いた。そのあと数分コードゴルフしたが全然縮まなかった。BCは特に言うことなし。Dはdp。

EはX\rightarrow Yという辺を張ったN頂点の有向グラフをトポロジカルソートすればよい。途中で使える頂点が2個以上同時にある場合ソート順が一意でなくなり答えはNo。そうでない場合、トポロジカルソートで得られた順列の逆順列がAとなる。コンテスト中はグラフにループがあるかも判定していたが、制約をよく読んだらそのようなケースはなかった。

Fは都市1からの最短距離と都市Nへの最短距離を前計算しておくと、kごとに都市kをまたぎ越す辺を全探索することで答えが求まる。そのような辺はO(M^2)本存在するが、今M\le 10なので十分少ない。

Gはシフトの回数を全部試すことができる。和にA_i|B_jが寄与するのはシフト回数が(i-j)\bmod N回の時なので、0\le a,b\le 31を固定してA_i=aとなるiB_j=bとなるjを集め畳み込むことで、シフトの回数に応じてa|bがどれだけ和に寄与するかを一気に計算できる。これは昨日話していたゆるふわ競プロオンサイトのE問題と一緒なので、かなりタイムリーだった。

そのまま実装しNが最大のケースで全然終わらないなあと言っていたが、当たり前。322回畳み込みするのが間に合うわけがない。冷静になると桁ごとに考えればよく、1桁につき(a,b)=(0,1),(1,0),(1,1)の3回畳み込む合計15回の解法を実装して1secで通した。後から(a,b)=(0,0)だけ計算して引くことで畳み込みを5回にできることに気づき、出してみたら500msを切った。

Gで少し手間取ったがここまでいいペースだな、と思って順位表を確認したら1ページ目が全完で埋まっていてひっくり返った。慌ててExを読むと重心分解せよと書かれており、検索して出てきたライブラリを写経したら通った。

1時間弱でノーペナ全完し38位。今日も動画を撮っていて、残り40分はかなりじっくりと各問題を振り返っていた。コンテストが終了してすぐに投稿。

www.youtube.com

コードゴルフはABCG。AをRubyで書く際、マッチした位置に1足して1-indexedにするのが面倒。入力を直接マッチングの左辺に持ってくると足す前に全体を括弧でくくる必要があるが、いったんgetsを実行してから~/[A-Z]/と書いて暗黙的に$_とマッチさせるとそのまま1足せるらしい。これで縮められた。

その後さらにVimで縮んでいた。大文字を探してそれ以降を削除した後wcコマンドに投げると、「改行文字込みの」文字数が取得できる。つまり見つけた大文字の前にある文字数に改行の分1増えた値が得られて、見事に1-indexedでの答えとなるようだ。

BはRakuが今のところ短いらしい。

Cは虚数単位iを「LRUD文字コードを15で割った余り」乗すると見事に複素平面での4方向に対応する値が得られたので、これを利用するRubyコードを書いた。しかし別のところで縮められ、さらにPerlでもっと短いコードが出て負け。

今のRubyの短縮ポイントは入力の2行目を得るのに[*$<][1]ではなく$<.maxが使えるというものだった。1行目は数値、2行目は英大文字なので、2行目のほうが辞書順で大きくなる。これは新手で、他にも2問ばかり縮んでいた。

Gは解説の定数倍の軽い方法をCPythonで実装したものが最短になっている。畳み込みした後添え字\bmod Nごとに値を集計していたが、長さNの巡回畳み込みができれば一発というのは目から鱗だった。ただNが2べきでないため、長さを変えずに高速フーリエ変換・逆変換するのは面倒。ライブラリに投げられる言語を使えば辛うじて、という感じだ。

午前8時まで日記を書いていた。AHCの自分の提出がシステスを終えており、確認すると2ケースでWAが出ていた。原因に心当たりがない。

布団に入り、寝る前にハーメルンの更新をチェックした。以下の作品に今日投稿されていた話がかなり長く、しかも非常に面白くて、じっくり読んでいたら寝るのが午前9時半になった。

syosetu.org

週記(2023/02/13-2023/02/19)

02/13(月)

午後4時過ぎ起床。30分近くかけて布団から這い出し、インターン先定例会に参加した。

進捗報告の場で共有されたことだが、自分が書いたコードがデプロイされた先でバグり散らかしていたらしい。すでに原因も特定されており、改めて見てみるとなんで気づかなかったんだと思うような単純なミスで愕然とした。一度正しく動くコードを書いた後、対応できていないケースが将来的に存在し得ることを発見し修正した部分。その修正が十分な範囲に及んでいなかった。

一応手元で書き換える前と後で出力が変化しないことを確かめたはずだから、試すデータが十分でなかったと考えていた。しかし今改めて思い返すと、ここがバグっていたら結構盛大に出力が変わるはずだから、もしかしたらそういうテストを全くしていなかったのかもしれない。目視でチェックしただけでいいやと思ってしまいかねないくらいの、本当に小さな範囲の修正だったのだ。

自分の見える範囲を離れた先でバグったということで、影響範囲が実感できない。だからこのバグが及ぼした影響も理解しておらず、正直な話いまいち真剣になり切れていない。一方で過剰に気に病むのも良いことではない。バグが発生するのは仕方ないから減らす努力をしましょうということを言われた。とりあえずはテストの充実化だろう。

その他は自分の進捗報告も含め特に何事もなく終了。勉強会は発表者が変わりつつ先週に引き続きAHC017の話だった。先週紹介されたDynamic Connectivityは実用性に疑問が残ると感じたが、今日は実際に高速化に寄与したいくつかの手法が紹介された。大体はグラフが平面的で、さらに辺のコストと頂点のユークリッド距離がほぼ等しいことに由来していると考えている。

試していないこととしてdijkstraを行う際の優先度付きキューをC++標準のものからフィボナッチヒープに切り替える高速化が挙げられたが、それが効くケースが出現しそうにないという理由で効果がないものと考えている。少なくともオーダー的な改善はM=O(N)なので存在しない。しかし自分も試していないため断言はできない。

先週同様質疑応答が盛り上がり午後8時終了。それからずっと週記を書いていて、日付が変わる直前にギリギリ投稿できた。今朝方何気なくJOI本選オープンに出たら週記を各時間を失った上書く内容も増えて大変だった。もともと今日は午後11時半からECRがある予定だったが、いつの間にか木曜日にずれていて助かった。

他人のブログ記事をいくつか読んだ後セミナー準備を開始し、午前6時くらいに完成した。今日は前回の残りがなかったため多少時間がかかったが、なんと明日は先生の用事で午後2時開始となっている。つまりこの時間まで起きていても全く問題ないのだ。

ゴミを出した。ほんの少し雪がちらついていてびっくり。天気予報によれば昼過ぎには止んでいるらしいし、今のところ路面に雪も積もっていないので、原付で登校できるだろう。

セミナーが午後2時開始という余裕と、原付で登校できるという余裕が合わさって、うっかり午前9時までラノベを読んでしまった。急いで就寝。

02/14(火)

なかなか起きられず、午後1時45分になってようやく布団から出た。原付で向かわないとギリギリの時間。しかし外を見るとまだ雪が降っていた。朝より勢いが増してすらいる。しばらく迷ったが地下鉄で登校することにした。この時点で大遅刻が確定したため先生にメールで連絡しておいた。

午後2時半にようやく教室に到着。その上買ってきた昼食を食べ始めるという有様だったが先生からは特に何も言われなかった。まあ何も言われないだろうと思っているからやっている。そういえば、昨年度の4年ゼミで同様のことをしたときは叱られたのだった。

教室に入って一息ついた段階で、途中で購買で買ったパンを食べようと思ったら、先生に止められた。僕はその時、本当にそのタイミングでパンを食べてよいと考えていた

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

午後3時半ごろまでは同級生の発表だった。今回から、正確には前回からグラフ理論の教科書を読んでいるらしい。自分が読んでいるDiestelとは違うもの。まずグラフの閉曲面への埋め込みに関する章を読み進めるようで、今日はその導入だった。自分もちょうどいまDiestelで平面グラフの章をやっているので、関連がいろいろあるだろうと楽しみにしている。

少し休憩して午後4時前から自分の発表。今日は準備してきたうち半分しか終わらなかった。また発表中、準備時に犯したミスにたくさん気づいた。幸い今日発覚したものはその場で修正できたから良かったが、こういうことが続くのはまずい。原因は明らかで、前日になって初めて教科書を読み、同時にメモを作っているからだ。何回か読むくらいは最低限やるべきなのだろう。

先週日記にも書いた以下の疑問についてTwitterのほうでリプライを頂いたので、セミナーの合間に少しやり取りしていた。足し算も階乗も原始再帰的だが、それと今の\Pi_1文などの話は関係なかったということらしい。講義資料で隣接しており混同してしまっていた。

素数が無限個存在する」、つまり「どんな数にもそれより大きな素数が存在する」ことを表すΠ1 Π 1 文を書く問題の解説がよくわからなかった。

週記(2023/02/06-2023/02/12) - kotatsugameの日記

素数判定の論理式で掛け算を使っているように、足し算や掛け算は普通考える算術に含まれるので変数の上界にも使えて、階乗はちゃんと\Pi_1文の範囲で再帰的に定義しなければ使えない。この観点から解答例を確認すると確かにそうしていた。なかなか誤植がひどくて意図を汲み取れていなかった。

学食で友人と会い、夕食を共にしてから午後7時過ぎ帰宅。早々に布団に入って寝落ちした。

02/15(水)

午前0時半に目を覚ました。先週末、というか月曜日の朝型オープンコンテストに参加したJOI本選のジャッジがAtCoderで公開されていた。オープンで提出したコードを一通り出したが特に得点の変化はなかった。

JOI 2022/2023 本選 過去問 - AtCoder

Bだけコードゴルフした。SCCは想定解ではなかった。|X_i-X_j|\le E_i-E_jという式を、絶対値を\maxで置き換えることでバラすとX_i-X_j\le E_i-E_jかつX_j-X_i\le E_i-E_jという式が得られる。それぞれ添え字を不等号の片方にまとめるとE_i-X_i\ge E_j-X_jE_i+X_i\ge E_j+X_jとなる。

つまり各住人を(E-X,E+X)にプロットしたとき、右上に他の住人がいない人を数えればよい。点を適当にソートすればできる。bashで書いたものが現在の最短となっている。

食事して布団に戻り、しばらくなろうを読んで午前5時くらいに寝落ち。

午後2時にまた目を覚ました。購買に行きたいが、すでに春休み期間に突入しているためあと1時間で閉店してしまう。それまでに起きて、シャワーを浴びて、歩いて大学へ……と考えるとどうにも気力が湧かなかった。布団に横たわったままなろうを読んでいるうちに閉店時間を過ぎ、その後午後5時にまた寝落ちした。

午後7時過ぎにまたまた目を覚ました。今回は特に何かしようとすることもなくひたすらなろうを読み続け、日付が変わるくらいに寝落ち。

02/16(木)

午前3時起床。昨日はずっと布団の上でなろうを読んでいるだけだった。食事も丸一日摂っていないのでひどく空腹。2時間ほど耐えてなろうを読み続けていたが、さすがに身を起こして食べ物を口にした。

トヨタコンのオンサイトで泊まるためのホテルを探した。いいものがまったく見つからない。最寄りが渋谷駅であるようなホテルはすべて目が飛び出るほど高い。その中でThe Millennials 渋谷というホテルは値段もちょうど良いし写真も綺麗だったが、よくよく調べるとカプセルホテルだった。それで普通のホテルと変わらない値段をしているというのは自分の常識の埒外にある。

渋谷駅から少し離れるとようやくそこそこの値段の宿が見つかった。いくつか見繕ったところで今日は終わり。

しばらく日記を書いた後、ラノベの注文をした。3月発売の新刊を中心に17冊。今回チェックした中で最も驚いたのは以下の本。カクヨムで読んだことのある作品の書籍化だが、そういう企画が進行しているのを全く知らなかった。覚えていなかっただけかもしれない。

famitsubunko.jp

kakuyomu.jp

昼過ぎに少しだけ生協に行った。今日は非常に天気が良く路面に積もった雪がすっかり解けたため、原付が使える。日陰に止めてあってまだ座面に氷が張っていたので、手で少し剥がしてから乗ったが、太陽の下に出たら残りもすぐに溶け消えた。最初からそうしておけばよかった。

予約していたラノベを受け取ったり菓子パンを買ったり昼食を摂ったりして帰宅。布団に入ってラノベを読み、午後3時前就寝。

午後8時半ごろに目を覚ましてずっとなろうを読んでいた。午後11時半からECR143。

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

Aはs+{\rm rev}(t)をどこで切るかという問題なので、この文字列で同じ文字が隣接するのが1か所以下かを判定する。

Bはl=kという線分がないとf(k-1)\lt f(k)とできず、同様にr=kという線分も必ず必要。逆にそのような線分だけ選べば条件を満たせるので、これが十分条件でもある。

Cはお茶iを味見役jがどれだけ飲むか考えると、j\lt iなら当然0、そうでない場合あるインデックスrが存在してi\le j\lt rならB_jj=rならA_iの残り、r\lt jなら0という風に分かれる。このrBの累積和上で二分探索することで求まる。一々jに対して答えを加算していられないので、B_jx_j+y_jという形で持ってxをimos法で更新した。

Dは、一つの三角形をどのように塗り分けても全体の重みに加算される辺は0本または2本となるから、すべて2本ずつ加算されるようにするのが最適で、実際に達成可能である。これで最大値は求まるのであとは数え上げ。まず各三角形について赤1個青2個で塗り分けるかその逆かを決める必要があって、全体で半々にする必要があるから{}_{n/3}\mathrm{C}_{n/6}通り。またどの辺を加算するかにも自由度があり得るので、三角形ごとに求めて掛け合わせる。

EはExplosionで選ぶiを全探索する。h_iを減らす理由はないので、左右独立に答えを求めて足すことを考える。右側だけ説明する。条件はh_i\gt h_{i+1}だが、これをh_i+i\ge h_{i+1}+(i+1)とすることで、単に右に見ていった時の累積MINに合わせればよいとわかる。同じ値で揃っている区間を持って更新していけばよい。h=0となってしまう部分は更新の度に取り除いておく。

Fは二分探索。操作回数を固定するとどの頂点から長さどれだけのパスを作ればよいかわかるので、本当に可能か木dpで求める。各頂点が持つのは「自分より下にいくつパスを伸ばせるか」または「自分より上にいくつパスを伸ばさなければならないか」で、なるべく葉のほうに押し付けながら遷移する。

Gは制約の「pは必ず一通り以上存在する」というところから考察を始めた。p_1となれる頂点はaの値とグラフの次数が等しい必要がある。そのような頂点は複数ありうるが、どの二つについても隣接することはあり得ず、またどれをp_1としてもpが作れるべき。以下同様に、すでに選んだ頂点に隣接する点の次数を減らしていって一度aと等しくなった頂点は、その後どのタイミングで選んでもよい。

逆にこれに違反するような順番ではpは作れない。具体的には、どの隣接する2頂点もpでどちらが先に並ぶかは固定されている。この関係はDAGになっていて、xからyあるいはyからxに到達可能なペア(x,y)のみがniceでない。その数え上げはbit並列によるO(N^2/w)しか知らないが、TLを確認すると4secだったので自信を持って提出。2sec弱で通った。後から頂点番号をトポロジカルソート順に振りなおしてメモリアクセスの効率化を図ったら1secを切った。

ちょうど1時間でノーペナ全完、2位。かなりうまくいったから手元動画を撮っておけばよかった。それにしても1位のtouristが圧倒的すぎる。

そのままTCB55に参加した。日曜日終了だからここに感想を云々かんぬん。こういう注意書きはどんな形であれ書いておく必要があると信じる。

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

4問目まではよい。5問目は\max(w_1,\dots,w_i)=iとなるようなiで切れるので、それを数える。6問目は、各整数についてそれが出現する最も左の位置をlとおくと、その整数がB_l,\dots,B_Nに1ずつ寄与しているので、lをsetを使って管理する。

7問目。まずインデックス\bmod Mで等しいとき集合も等しいということを満たしたい。対応する集合の共通部分を取っておくと、その部分集合なら何にでも揃えられることがわかる。よって残りは集合が等しければインデックス\bmod Mが等しいということを満たすだけ。

\{0,\dots,9\}のすべての部分集合について、それに含まれる集合にしか揃えられないインデックスを数え、作れる部分集合の数より大きくなっていないか確かめるというコードを書いた。しかしWA。集合の要素がもともと0-indexedなのに1引いているのに気づき直したがまだ1ケース落ちている。

実はこの判定方法が怪しいことはわかっていた。じゃあなんで提出したのかという話だが。冷静になるとインデックスと集合を対応付ける二部マッチングで解ける。2WAしたので-22pt。TechFULのコンテストでペナを付けるのはかなり久しぶりな気がする。

8問目。手で実験すると、S_kの先頭(k-1)!項の操作を行うごとに数列は先頭k項が後ろに一つrotateされるとわかる。この操作列は同じものが繰り返してk-1回現れているから、例えば入力だと最初のa_{N-1}(N-1)!回の操作で数列全体がa_{N-1}回rotateされることになる。さらに残りの操作列はS_{N-1}だと思ってもよいので、以下再帰的に処理できる。

実装では、数列がrotateされた回数を管理しつつ、a_iを処理するタイミングでv_{i+1}の値を確定させていった。残っている数のうち何番目に大きい数が該当するかわかるので、BIT上で二分探索して取得すればよい。

9問目は準開基を知っていますかという問題で、知っているので解ける。\mathfrak{M}(に\{0,\dots,N-1\}を追加したもの)から有限個の元を取ってきて共通部分を求めると開基になっていて、この開基に任意個の和集合を取る操作で閉じるように集合を追加したものが\mathfrak{M}を含む最小の位相になっている。自分は学部2年で習った。

上に書いた手順をそのまま実装すればよい。開基\mathfrak{B}を求める際は、O\subset\{0,\dots,N-1\}が入っていることを\bigcap\{O_i\in\mathfrak{M}\mid O\subset O_i\}=Oによって判定する。そこから作る位相にU\subset\{0,\dots,N-1\}が入っているかは、\bigcup\{O\in\mathfrak{B}\mid O\subset U\}=Uによって判定する。前者で適当に包除原理を使ったら2個以下の共通部分しか求めておらず1WA、-15pt。

10問目は結構面白かった。各Xに対しf^K(X)=Xを達成するfを数える。このXはすべてループに乗るから、まずそのループだけ考える。「これまでいくつの要素の行き先を決めたか」と「そのうちいくつをXに含めたか」を持つ2次元dpを書いた。

それぞれijとおく。次に作るループの長さをlとすると、ループへの要素の並べ方が円順列を考えて{}_{i+l-1}\mathrm{P}_{l-1}通りある。このループをKステップ進むと、要素はg=\gcd(l,K)としてサイズl/gのブロックg個に分かれるから、0\lt n\le gに対しXn\times l/g個追加する方法が\binom g n通りある。重複して数えるのを避けるためn=0は許していない。

最後にすべての(i,j)について、求めた場合の数に残りN-i要素の選び方と行き先合わせて\binom N i\times N^{N-i}を掛け、足し合わせれば答えが求まる。とりあえずこれでサンプルが合った。計算量が\Omega(N^3)だが、よく見るとjの情報を使っていない。これでO(N^2)になってAC。正確には\gcdを毎回求めているので\logをつけている。少し時間がかかって-2pt。

合計で-39ptだった。今回の9問目は問題文の読解から完全に知識ゲーでヤバいと思う。「最小の位相」という用語に定義がないのが気になる。

朝まで日記を書いた後、1時間ほどインターンの進捗を産んだ。今日触ったコードはいずれ先週立てたサーバと通信して動かす予定だが、まだそこまで完成してはいない。

オンサイトのホテルを決めて予約した。もともと前泊のみの予定だったところ、イベント直後にUniversal Cupを走る予定になったので後泊もすることにした。本来なら少し余裕をもって仙台まで帰れるはずなので2泊分の宿泊費を出してもらえるかはわからない。ダメだと言われたら1泊分は自分で払う予定だ。いろいろ探して、伝えられていた相場より少し休めのホテルにした。

実は上のほうで触れたカプセルホテルThe Millennials 渋谷には結構興味があった。共用部が充実していると聞いたから談話室みたいなものを想像していて、そこで競プロ談義したら楽しいだろうなと思っている。しかしコンテストに出るには向かないので避けた。

午前10時頃布団に入ったものの、なぜか目がさえていた。1時間近くYouTubeを眺めてようやく眠りに落ちた。

02/17(金)

午後2時直前に起床し1on1。

今朝がた産んだ進捗を説明した後、サーバと通信できるようにしようとしたが、認証回りがうまくいかない。2時間の1on1のうちほとんどをこれに費やした。結局1on1終了後少し経ってから解決したらしく、方法を教えていただいた。以下その説明。単に技術的な話題なのでここに書いてもよいだろう。

やりたいことというのは、Basic認証の先にあるAPIを叩くことだった。Basic認証を突破するために、AuthorizationリクエストヘッダーにIDとパスを渡す必要がある。一方でAPIを叩くためには同じ方法でTokenを渡す必要がある。これが被っていて、同時に渡す手段がなく困っていた。

APIのTokenを別のヘッダーで与える方法で解決できたようだ。Basic認証をかけているnginxの設定ファイルを書き換えることで、そこを通過する際にToken情報を正しいヘッダーに渡すことができる。もともとそこに入っていたIDとパスはすでに使い終わっているから必要ない。あとは通常の通信と同様に進むということらしい。

また1on1後に月曜日に言及したバグが修正されたので、自分でも直っているか確かめていた。手元で実行したら修正前後の出力で大量にdiffが出たので、どうやらバグを埋め込んだ当時は本当にチェックせずコードをpushしてしまったらしい。大反省。

午後6時前に外出。まぜそばを食べてゲーセンに向かい閉店まで遊んだ。今日は眠くて大変だったが、なんだかんだ理論値を四つ出した。マーシャル・マキシマイザーは好きな曲なので頑張って粘着した。手元動画も撮った。

閉店後立ち食いそばを食べ、ドンキで菓子パンやお菓子を買い込んで帰宅。途中にある公園でブランコを漕いだりして少し遊んでいた。

帰宅してから手元動画を投稿し、シャワーを浴びて布団へ。ラノベを開き、「才女のお世話」4巻を読了した。

3巻を読んだのは半年以上前らしい。その巻のヒロインが幼馴染ポジションだと思っていたが、彼女は一時期共に過ごしていただけで、この巻のヒロインこそが真の幼馴染だった。名前だけは1巻から出ていたので、いよいよ登場かと思うと嬉しさがある。

主人公の成長を彼女は知らない、ということがこの巻のメインだったと思う。最後に解決するまではなかなか辛い展開だった。舞台となった夏季講習で主人公が受けている授業の内容が彼女にとっては非常に難しく、少しわかると虚勢を張りつつ主人公も太刀打ちできないだろうと思っていたら、かなり良い成績を叩き出されて愕然……という描写があった。特に虚勢を張るあたりがなかなか自分に刺さった。

個々のシーンとしては好みのものが多かった。夏期講習の場でも、休日の海水浴でも、ヒロインたちは注目を浴びている。主人公がそういうところに意識的なので、自然に関連する描写が増えて嬉しい。

午前7時就寝。

02/18(土)

正午直前に起床してAHC018開始と同時に問題を読み、提出はせずまた寝た。このタイミングで問題を読んだことは順位表から分からないが、これくらいは書いていいだろうと思っている。

RECRUIT Nihonbashi Half Marathon 2023 Winter(AtCoder Heuristic Contest 018) - AtCoder

今度は午後2時直前に起床してUniversal Cup 4回目に参加した。今日のセットはUkraine由来。問題文が短くて非常に読みやすかった。チームでAEIKFCBJを解き、8完66位。自分はAKCBを担当した。

Dashboard - Anton Trygub Contest 1 (The 1st Universal Cup, Stage 4: Ukraine) - Codeforces

先頭から順番に読み始めた。Aの問題概要を理解した後、すぐにはわからないと思ってBに進んだが、一番最初にFAが出たので慌てて戻ってきた。よくわからないままサンプルの四つ目を見てそれっぽく並べ、しばらく証明っぽいものを考えたり順位表でほとんどペナが出ていないのを確かめたりしてから提出。無事通った。結局証明はできていない。

次にFAが早かったEがかっつさんによって通された。二度ほど提出して両方落ちたかに見えていたが、いつの間にかリジャッジが来ていて最初の提出が通っていた。

solved数を見てぷらさんがIに、自分がKに取り組んで、立て続けに通った。Kは半ばエスパーで強連結成分が1個かチェックするコードを出した。

全頂点を通る有向閉路が取れればその閉路に沿って要素を並べられ、その後好きな順列にできることは分かっているが、関節点があるとどうなるかよくわかっていなかった。日記を書いているときに改めて考え、有向閉路の上で好きに並べ替えられるのだから適当にswapを実現すればよいことに気づいた。

この後自分がC、ぷらさんがB、かっつさんがFに取り組んでいた。少し経ってからFが通り、自分もCを通した。

基本的には左からdpしていく。見ている位置より左にあるパスの数が状態。閉路の重みを最小化するのだから、新しい頂点を追加するときはできるだけそれを使って2本のパスを繋げたい。繋げるパスがない場合は新しく1頂点のパスを追加するしかない。あるいは、このタイミングで繋ごうとすると小さな閉路になってしまうケースもあって、その場合はどちらかの端点を伸ばすだけになる。

以上3種類の遷移のうちどれが行われるかは、見ている位置より左にあるWBの数の差が1歩右に進むことでどう変化するかによってのみ変わる。つまり状態数が常に たった一つなので十分間に合いそう。しかしよく考えると、長さ2以上のパスはどちらの端点で繋げるかで2通りの自由度があるのに、長さ1のパスはどちらも変わらない。これらを考慮して場合の数を求める必要がある。

長さ1のパスの本数を持ちたくなったが、実はパスを作る・伸ばすときに次に使う端点も決めてしまうことで、変わらず一つの状態で扱える。場合の数を2倍するのを先に行っておくというアイディア。最後、閉路にするときだけ端点を区別しなくてよいので、答えを2で割ってから出力する。頂点は四つ以上あるので必ず不必要な2倍が行われている。

以上の説明はコンテスト後に考えたもの。コンテスト中は端点が2本または1本生えている頂点がたくさんあるという捉え方だったので、端点を二つ繋ぐとその相方同士を新しくペアにして考えてよいということに気付くのにも時間がかかったし、2倍するタイミングも結構ガチャガチャして無理やりサンプルを合わせていた。

ぷらさんがBで詰まっていたのでバトンタッチした。このタイミングでは自分がB、ぷらさんがJ、かっつさんがDに取り組んでいた。

BはFAが9分だしこの時点でsolved数もかなりある簡単枠に見えていたのに、取り組んでみるとかなり苦労した。実験結果から同一のnに対して\gcd(n,k)が同じなら答えも同じになるようだったので、k\leftarrow\gcd(n,k)として考えることにした。

最も単純なケースでは、同じ周期kを持ち1周期の和が一致するabについてf(a)=f(b)である。これでは十分に重複を省けていないが、k項ごとに区切るのは良いのではないかと考えた。f(a)_2=f(a)_1-a_1+a_{k+1}なので、k項ごとの値の変化に注目する。01列の値の変化と言えばXORである。

長さnの01列を先頭k項とその後ろに分け、後者については値そのものではなく、ちょうどk項前の値とのXORn-k個で表現する。こうしても当然2^n通りあって、すべての数列を漏れなく重複なく表現できる。列abf(a)=f(b)を満たす場合、この表現にどういう関係があるか考えた。

まず明らかに先頭k項の和f(a)_1f(b)_1が一致している。さらに、そこから和を取る範囲を1項ずつずらした時の変化が等しいのだから、a_{k+1}-a_1=b_{k+1}-b_1のような関係がn-k個ある。正確にはn個あるが最後のk個はそれ以外から復元できる。

この関係はほとんどa_{k+1}\oplus a_1=b_{k+1}\oplus b_1なので、少なくとも表現におけるn-k個のXORは完全一致する。しかしこの書き換えは十分性を失っている。

XORが0の場合はよいが、1の場合例えばa_1\ne b_1だとXORが一致しても差は一致しないことがわかる。逆に1\le i\le kについてa_i\ne b_iならa_{k+i}\oplus a_i=a_{2k+i}\oplus a_{k+i}=\dots=0という条件を加えると十分になる。

ここでXORn-k個を固定して数え上げることを考える。1\le i\le kで独立に扱えて、各iに対しa_{k+i}\oplus a_i=a_{2k+i}\oplus a_{k+i}=\dots=0となるのが1通り、そうでないものが2^{n/k-1}-1通りある。前者をタイプ1、後者をタイプ2とし、タイプ2が0\le c\le k個あるとして先頭k項について考えてみる。

改めて、そのようにXORを決めた元でf(a)=f(b)となるようなabの先頭k項の関係を書く。まず総和が等しいことが一つ。次に、タイプ2に対応するiではabの値が一致していることが一つ。これで必要十分なのだった。

重複を数え上げるのではなくf(a)の種類を数え上げようとすると、タイプ2の部分が異なるか、タイプ2の部分で一致してもタイプ1の部分で総和が異なるようなものを考えればよい。前者は2^c通りあり、後者は0\dots k-ck-c+1通りある。

以上をまとめると、求めるものは0\le c\le kに対する\binom k c (2^{n/k-1}-1)^c2^c(k-c+1)の和となった。とりあえずこれで実験と答えが合う。マルチテストケースでnの総和に制約がないのでO(n)のこの式は間に合わないが、Wolfram|Alphaに投げたら閉じた式になった。無事AC。

残り2時間。JとDで迷って、Dはよくわからない構築っぽいと感じたのでJをぷらさんと一緒に考えた。1回操作するごとに順列全体の転倒数の偶奇が変わるので、1回おきに答えがnとなる。そうでない場合を考える。まず自明なケースとして、順列がソート済みだと答えは-1。これはp_i\gt p_{i+1}なるiをsetで持っておくと差分更新でチェックできる。

そうでない場合、答えの下界はn-2だと分かった。p_i\gt p_{i+1}なるip_iを取り除いてもp_{i+1}を取り除いても転倒数が偶数のままなら、両方一緒に取り除くことで奇数にできる。よって答えがn-1かどうかを判定する問題になった。

ここで、各iに対し「p_iを取り除いたときの、転倒数の変化の偶奇」を管理する。p_up_vをswapするとき、まず、その前後でuv以外のインデックスに対応する値は変化しない。

またp_uからp_vに変化したインデックスuに対する値は偶奇が|p_u-p_v|だけ変化するとわかる。(p_u,p_v](あるいは[p_v,p_u))の範囲にあるpとの各ペアについて、転倒数に寄与する・寄与しないが一斉に切り替わるからだ。vも同様。

これで解けたので実装をぷらさんに託しNを考えていた。たくさん場合分けをして簡単なケースから考えていたが、メインのケースに突入する前に詰まってしまい、ちょうど書き上がってサンプルが合わないらしいJのデバッグに回ってその後戻ってこられなかった。

Jのコードを共有してもらってかなり長い間眺めていたが、まったくバグが見つからなかった。しかし手でサンプルを試した瞬間解法の伝達ミスを発見。上ではiについて値を持っていたのに対し、コードではp_iについて値を持っていたのだ。それ以外の考察にミスはなく、ここを修正したら即座にサンプルが合ってそのまま通った。このデバッグに1時間弱かけていて、手を動かさずコードを読むだけで済ませようとしたことを反省した。

最後の数分はDを考えていた。これまで何度も提出されていて、どれも落ちてしまっている。コードを読んでもよくわからず諦めモードで問題を眺めていたところ、ふと思いついた構築がどんぴしゃりの正解だった。a_{i,j}=1なるijの間すべてに辺を張り、条件を満たしているか確かめるというもの。残り5分くらいでかっつさんに急いで解法を伝え実装してもらったが間に合わなかった。

この構築の正当性について。まずa_{i,j}=1ならd_{i,j}=1となるため良い。そうでない場合頂点ijの間の最短経路は長さ偶数のパスとなってほしい。そのようなパスが存在するなら、適切に切ると頂点kであってikの間、kjの間の最短距離が奇数となるようなものが取れて、a_{i,k}=a_{k,j}=1となっているはず。よって今作ったグラフではikjという長さ2のパスが存在しd_{i,j}=2となる。

こういう考察をしておくと、「条件を満たしているか確かめる」と言いつつ実際はa_{i,j}=0なるijに対して上のようなkが存在するかチェックするだけでよい。コンテスト終了後に自分で実装してみたらなんと2分で終わってしまった。中途半端に解法を伝えるのではなく、かっつさんから実装を奪い取って自分で書くのが正解ムーブだったらしい。

少し休憩してから感想戦。Eは三つ以下の分割さえ考えれば良いというのは典型的な考察だと思ったが、そのあとのチェックが思ったより大変そうだった。

Iはa_{i,j}\leftarrow a_{i,j}-i-j+1と補正するとすべて0以上かつa_{n,m}\le 1より最大値が1となるようで、あとは行・列が「広義」単調増加となるように01を並べる問題。この初手は問題を読んですぐ出てきたらしいが頭が良すぎる。

Fはかっつさんによって2部グラフで長さ4のサイクルを求める問題に帰着され、自分がABCで既出だなあと言っている間にぷらさんが具体的な問題を見つけてきて下さった。

F - Find 4-cycle

自分はBとCの解法を整理できておらず、合わせて1時間近く話したうえ最後まで説明しきれなかった。感想戦をすることを自分から提案しておいてこの体たらくとは。上でその二つの問題について、特にBについて長々と書いたのは、それを埋め合わせとするつもりだったから。書き上げたのが日曜日の朝方で、無事広義でコンテスト当日のうちにチームに共有することができた。広義でというのは、自分がまだ寝ていないから当日中だということ。

そんなことがあって感想戦が終わったのは午後8時半だった。菓子パンを食べて午後9時からARC156。

AtCoder Regular Contest 156 - AtCoder

Aは場合分けを繰り返して解く。1の個数が2個でないケースはすぐ処理できる。そこから1回で達成できるケース、2回で達成できるケースを取り除くと残りは本当に少なくなって、個別に対処できる。実際の考察では最初に3回で達成できるケースを思いついていたので、特に引っかかることはなくノーペナで通った。

Bは簡単。最初から書かれている数を無視して新しく書き込んだ数の最大値を固定すると、それを達成するのに最低限必要な操作が一意に定まり、残りは最大値以下から多重集合を自由に決めるだけで重複なく数え上げられる。

Cは難しかった。サンプルが貧弱だが両方類似度が1なので、たぶん常に1とできるのだろうと考えた。木からある1点を取り除くとちょうど半分ずつの連結成分に分かれたとして、それぞれの番号がPではごっそり入れ替わっていると良さそうに見える。実際はダメダメだが、考察はここから得られた。

ちょうど半分ずつに分かれるというのは強すぎる仮定だから、適当に根を決めたときにそれぞれの部分木を入れ替えるくらいで考えておきたい。まず根の直接の子だけ見てみると、番号をrotateしてPとすることで、根を含めどの二つも同時に共通部分列に含まれないようにできていると気付いた。

ここから、同じ深さにある頂点を集めて番号をrotateすると良いのではないかと予想した。根以外のどの深さにも2頂点以上あってちゃんとrotateが行われているとし、適当に図を描いて確かめてみたところ、本当に類似度が1になっていた。パスの頂点の深さが順に上がって下がってという変化しかしないことを考えると、どの2頂点もPにおいては逆順に出現してしまうとわかるので、これで証明もできた。

深さに関する条件は根を直径の中心の1点あるいは2点とすることで達成できる。実装してからO(N)のコードになっていることに気づき、制約がN\le 5000なのを訝しがりながら提出。ジャッジが微妙に遅いのを見て、ようやく類似度1の判定が\Theta(N^2)なのだろうと感づいた。無事AC。

Dは面白かった。\sum A_Xが等しいXはたくさんあるだろうから、まず同じ値になるXを数え上げ、それが奇数になるものだけ計算するという方針が立つ。c_j=\#\{X_i=j\}と定め、これについて考えた。cが同じなら当然\sum A_Xは等しくなる。

cに対してXがいくつあるか数えるのは多項係数だが、二項係数の積で書くこともできる。\binom{K}{c_1}\binom{K-c_1}{c_2}\dots\binom{K-c_1-\dots-c_{N-1}}{c_N}だ。これが奇数だというのだから、Lucasの定理を\bmod 2で適用できる。

整数を2べきの集合だと思うと、まずc_1\subseteq K。このときK-c_1K\setminus c_1を同一視することができて、c_2\subseteq K\setminus c_1となる。以下同様。よって考えるべきcの条件は\bigsqcup c=Kとなった。非交和であることに注意。

これでかなり状態数が減ったので、dpを考え始めた。c_1から順に決めるのは、和とXORにそれほど嬉しい関係がないためできない。一方Kの立っているbitを下からcのどれに割り振るか考えると解けるようになった。和において今後更新されない下のほうのbitを無視できるので、持っておく値の種類数が十分少なくなる。

実装したらサンプルが合ったがWA。しばらく考えて、無視してしまった「今後更新されない下のbit」の扱いにミスを見つけた。無視する際無条件で答えにXORしていたが、場合によっては答えに偶数回寄与するためXORしてはいけないものもある。具体的には、Kにおいてまだ決めていないbitの数をm個とすると答えにN^m通り分寄与するため、その偶奇を見る必要があった。

かなり盛大なミスだと思ったが、確かにサンプルでは落ちないようだ。修正したら通った。

Eは解けなかった。条件がS=\sum XとしてSが偶数かつすべてのiについてX_i+X_{i+1}\le S/2だと分かったが、数え上げるのが面倒すぎる。包除をするつもりだった。X_i+X_{i+1}\gt S/2となるようなiについて、実は同時にX_{i+1}+X_{i+2}\gt S/2ともなれるので2個ある可能性があり大変。

Sが偶数という条件だけで数え上げるのはサイズが大きくて難しい。まずここが解けていない。一方包除で取り除くべきケースについてはX\le MよりSがそこそこ小さいので数か所で全探索を使えるのだが、O(1)で計算すべき場合の数もたくさんあって、それがひたすらしんどかった。変数の範囲に制限があって、二つの和が固定されていて、何通りありますか?みたいなものだ。

整理しきれず終了。4完14位だった。

コードゴルフはAのみで、入出力回りで大敗。範囲演算子フリップフロップとして使う際の評価戦略を利用するテクはAWKならよく見るが、他の言語では初めて見た。行番号を簡単に見ることができるので今回強いようだ。そういう機能の存在は辛うじて見覚えがあるとはいえ、自力で思いつけるとはとても思えない。

perlop - Perl の演算子と優先順位 - perldoc.jp

ARCの動画を投稿した。手元でエンコードしてファイルサイズを落としてから投稿しようと思ったら、逆に2GBくらい増えてしまったため、今回も撮ってそのままアップロードしている。

www.youtube.com

しばらくなろうを読み、朝方まで日記を書き、布団に入ってからラノベ「才女のお世話」5巻を読了した。

前巻から引き続いて主人公の過去に焦点が当たっていた。メインヒロインがいよいよ自分の恋を自覚するという展開。これまでの恋と親愛をごっちゃにしたような甘えっぷりも良かったが、4巻に渡って十分堪能したので、ここで一歩進むことは歓迎したい。シーンとしては主人公が昔暮らしていた町をヒロインと歩いているときにヒロインの美しさで注目を浴びるところが好みだった。

シャワーを浴びて布団に入り、少しなろうを開いたところ一瞬で寝落ちした。正午くらいだった。

02/19(日)

午後7時半起床。コンテストに出る準備をした。今日は午後8時からCFで5時間コンテスト、さらにその間にいつもの時間でABCがある。両方同時に参加したが日記では別々に書く。

まずCFの5hから。

Dashboard - SWERC 2022-2023 - Online Mirror (Unrated, ICPC Rules, Teams Preferred) - Codeforces

Aはよい。Bを読んで区間dpを書き始め、思ったより難しかったのでいったん諦めて以降はsolved数を見て開いていった。

Hはbのsuffixでaの部分列となるようなもののうち最長のものの長さを答える。

Lはsに含まれる+-p個、n個と置き、aのボタンを+で押したのがp_a回、-で押したのがn_a回とすると(p_a-n_a)a+( (p-p_a)-(n-n_a))b=0が条件になって、整理するとp_a-n_a=(n-p)b/(a-b)となる。a=bのケースに注意。p_a-n_a-n以上p以下の整数にしかなれないので、そうなっているか判定。

Fは基本的に、ある1頂点から出る辺とそれ以外の辺に分ければよい。次数がn-1未満の頂点を選べばそれで条件を満たせる。そのような頂点が存在しなければ完全グラフで、この場合1頂点から出る辺をさらに2分割することで対応できる。

Gを考えている間にABC開始時刻になり、2時間弱そちらに取り組んでいた。戻ってきて改めて考えても解けなかったため、いったん離れて別の問題を解いていった。

Bは相変わらず区間dp。マージの際一番下のブロックの位置に自由度があってどうしようかなと思っていたが、よく考えるとマージの対象となった区間の左端・右端のブロックからそれぞれ右下・左下に伸びる直線の交点にあると思ってよい。自由度とは実はそれだけしかないはずだ。よって区間以外の情報が必要なくなり、ちゃんと間に合うdpができる。

Jは結構面白かった。元の頂点が2^k倍になっているので、2進数でk桁の添え字をつけることで管理する。張られている辺は3タイプある。まず元の頂点が同じで添え字がちょうど1bit違う2頂点の間に辺がある。元のグラフにおける辺は、端点が同じ色なら同じ添え字を持つ頂点間の辺になり、違う色なら添え字が対称、つまり合わせると2^k-1となる頂点間の辺となる。小さい範囲で実験して気づいた。

ここから実際に直径を求める。片方の端は対称性から添え字0の頂点だとしてよく、n通り試すことにする。そこから元のグラフでBFSすることで、各頂点で添え字0の頂点までの距離、添え字2^k-1の頂点までの距離が求まる。

途中の頂点の中で添え字を変えるような移動を行うのは終点で行うのと変わりないので考えなくてよい。よって後は、どの添え字が一番遠いかをそれぞれの終点について求めるという問題になる。立っているbitの個数にしか興味がないので考えるべき候補はk+1通りしかない。O(1)で求まるはずだが計算量に余裕があったので全部試した。

Cに進んだ。できるだけ区間を半分にしていくような貪欲に基づいて実装してみたらサンプル2が合わず、半分にするのは最適ではなかったと気づき諦めた。

この時点でGが200人以上に解かれていたが自分はまだわかっていない。他の問題に進むよりこれを通すべきだろうと考え、改めて取り組んだ。しばらく考えて天啓がひらめいた。実は長さn区間n個に含まれるWの個数の最大値が答えとなる。なぜなら、Wが足りない区間は適切に延長することで必要な個数を確保できるし、延長の向きを制御することで区間が被ることもないから。

合計で1時間くらい使ってしまったが、こういう発想一発のような問題はすぐ思いつくか一生思いつかないかだと考えていたので、長い時間を使って解法に至れたのは驚きだった。

少しIを読んだ後Cに戻ってきた。もうしばらく適当な貪欲を試した後、方針を切り替えた。あるxについて全体を幅x-1区間に分割したとき、x以上の区間を使い切る前に分割が終われば後手勝ち、そのようなxがなければ先手勝ちとするもの。

先手はxを降順に使い、現在の分割で残っている最大の区間を選び左端を端点とするという戦略。後手は分割する点を列挙しておき、できるだけその点を取ろうとする戦略。実装して提出するとTLEで、それを修正しているうちにコンテストが終了した。TLEの原因はsetの末尾にアクセスしようとしてしまっていたからで、後から投げなおしたらなんと通ってしまった。数分足りなかったということで残念。

結果は8完89位、良くない。次にABC290について。

Toyota Programming Contest 2023 Spring Qual B(AtCoder Beginner Contest 290) - AtCoder

ABはよい。Cは0から順番に一つずつBに入れていき、必要な数がAになくなるかBのサイズがKになったタイミングでやめると次の数が答え。

Dは印のついていないマスだけ見てDマス進むのではないのがポイント。g=\gcd(N,D)とするとN/g回操作するごとにxがループして手順iiが1回だけ行われるので、その回数を手順iだけ考えた時の番号に足すことで答えになる。

Eは主客転倒で数のペアに対しそれが答えに寄与する回数を数える。操作が必要な数のペアはたくさんあるので、逆に操作が必要ない、つまり値が等しいペアについて考えて全体から引く。その全体は|X|を全探索することでO(N)で求まる。

i\lt jかつA_i=A_jとして、このペア(i,j)が対称の位置に来るようなX\min(i,N-j+1)通りあるから、ijを動かして足し合わせたい。Aが等しいインデックスだけ集めた列を作り、その中からjを全探索すると、\min(i,N-j+1)=iとなる範囲が列の二分探索で求まるので、iを動かしたときの和が計算できる。

Fは結構難しかった。Xから木を作るのは難しいと考え、木からXを作ろうとしていたが、考えているうちにX_i\ge 2なるiを全部一直線に並べるだけで直径の最大化ができると気付いた。

その頂点数をkと置くと選び方が\binom{N}{k}。並べ方は考えないので順列ではない。残りのN-k頂点の次数は1だから次数の余りが(2N-2)-2k-(N-k)=N-k-2だけあって、これをk頂点に割り振るので重複組み合わせで計算すると\binom{N-3}{k-1}通りとなる。これに直径k+1を掛け、和を取ると答えになる。

Wolfram|Alphaで計算した。最初直径を掛けるのを忘れていたら\Gamma(N-1/2)/\sqrt{\pi}のような式が出てきて、頑張って二重階乗に直したのだがサンプルが全然合わなくて愕然とした。正しい式を入力したら単なる階乗だけで書けてしまった。

G。連結成分のうち深さ最小の頂点を固定して考える。その頂点が葉からd段(0\le d\le D)上にあるとすると、それ以下には最初にK^0+K^1+\dots+K^d頂点あって、ここから適当に頂点を切り落としてXにするのが目標。

葉からk段(0\le k\lt d)上った先の頂点以下を切り落とすと、頂点数はK^0+K^1+\dots+K^kだけ減る。つまり額面がその値であるようなコインがd種類あるので、枚数を最小化しつつ必要なだけの頂点を切り落とすという問題になった。本当は切り落とすべき頂点が残っていることも確認しなければならないが、たぶん大丈夫だろうと思った。

コインの額面に約数・倍数の関係がないので、貪欲に取ってよいのかわからない。ダメだと思ってしばらく考えてみるも全然解けず、本当は大丈夫なんじゃないかという気持ちになってきた。K=2,3で小さい範囲を試し、貪欲が成立していることを確かめて提出したら通った。この貪欲が正当なら1種類のコインをK+1枚以上使うことはないので、切り落とすべき頂点が必ず残っていると言える。

Exは解けず。両側から小さい値を順に埋めていくO(N^2M^2)のdpを書いたが、合っているか間違っているか以前にTLEで全然ダメだった。適当に探索する範囲を絞るも手元で2.7secくらいにしかならなかった。

7完18位。Gの貪欲は正当らしい。公式解説にQiitaの記事が貼ってあった。なんだか見覚えがある。額面が約数・倍数関係にあるより弱い条件があったということは記憶していたが、探しに行かなかったのが敗因か。

硬貨の問題が貪欲法で解けるための条件 - Qiita

CFが終わってからコードゴルフを始めたが、もうあらかた縮め終えられていた。とりあえずコメントのしようがないものから、Aはdc、DはRuby。EのPerlはそもそもアルゴリズムを理解していない。これとBCF以外、つまりG以降は手付かず。

BはVimで、あるかわからないK+1個目のoを探す方針がうまくいかないのはわかっていたがK個目を巻き込んでxに直してから改めて1文字だけoにするという方法で回避できるらしい。こういうoff-by-oneの回避はVimコードゴルフの花形という感じがして、自力でできた試しがない。

CはRuby0\dots K-1からAに含まれない値のうち最小のものを探し、なければKを出力するというもの。操作回数云々をちゃんと言い換えるとこうなるようだ。何も考えていなかった。

FもRuby(N-1)!(N-2)!の逆元を計算したいとき、(N-1)!^2/(N-1)と見ることで逆元を2乗するだけになり短くなるようだ。その2乗は逆元を求めるときに{\rm mod}-2乗する代わりに2{\rm mod}-4乗することで行える、という更新で掠め取った。しかし冷静になるとこれは{\rm mod}-3乗である。結局最短コードは取れなかった。

TCB55が終了していた。4位。

今日のCF 5h+ABCは動画を撮っていたので投稿した。今回は自分の書いているメモがそのまま読めるよう手元を縦向きにしてみた。動画時間が5時間あるのでチャプター分けが大変だった。

www.youtube.com

朝までうっかりなろうで時間を浪費してから日記を書いた。午前10時半就寝。

週記(2023/02/06-2023/02/12)

02/06(月)

午後4時半に起床し、即座にインターン先定例会に出席した。

先週木曜日に書いたコードが進捗。その翌日の1on1で今週のタスクについても指示されているから、発表内容には特に困らなかった。

勉強会はAHC017の話。せっかくインターン先がスポンサーとなったコンテストだったのに初日にコードゴルフしてから何も触れられなかったので、ちょっと負い目を感じている。辺の追加・削除を処理しつつグラフの連結性を判定したくなるらしく、Dynamic Connectivityが紹介された。それが効果的だったかはともかく、名前だけ知っていたアルゴリズムの一つとしてこの機会に実装の概要を学べたのはよかった。質疑応答が盛り上がり終了は午後8時となった。

先週土曜のABC288が予選となっていたToyota Programming Contest 2023 Springについて、決勝進出メールが届いていた。夏の第三回日本最強プログラマー学生選手権と同様前泊するつもり。近辺のホテルが続々埋まっているらしいが、遠慮せず上限ギリギリの値段で探せば十分見つかるだろうと思っている。

週記を書いて午後11時に投稿。それから2時間くらいYouTubeで時間を溶かしてしまった。

MF文庫Jの2月の新刊について、表紙イラストやあらすじが公開されていた。自分が非常に楽しみにしている「Vのガワの裏ガワ」2巻も2月発売。あらすじだけでどんな話になるのだろうかとワクワクが止まらない。イラストも良い。表紙の構図は1巻とほぼ同じに見えるのに、色合いが寒色から暖色に変わると受ける印象が全然違って面白い。

mfbunkoj.jp

午前1時からセミナーの準備を開始した。前回の残りが5ページくらいあるので、追加でほどほどに準備しておけば十分そう。教科書ではしばらくちょっとした命題とその証明が連続するので、上からいくつか読んでまとめ、4ページ程度メモを作成した。午前4時終了。

布団に入って少しなろうを開いたがすぐ寝落ちした。

02/07(火)

午前9時半起床。今日は空模様が悪そうだが、降るのは雪ではなく雨らしい。積雪ももう溶け切っているようだから原付で大学に向かった。

購買で朝食を買い少し遅刻して教室に到着、セミナー開始。同級生は今回セミナー準備がうまくいかなかったらしく、すぐ自分の発表になった。前回の残り5ページを話し終えたくらいで正午になりいったん休憩。購買でパンやおにぎりを買って昼食とした。

その後すぐ自分の発表が再開したわけではなく、博士課程の方の発表が2時間ほどあった。年明け初回のセミナーで詰まっていたところからようやく少し先に進んだ気がする。1か月経っているように見えて、集中講義や博論発表会で2回ほど博士課程の方のセミナーが潰れているからそんなものかという気持ちになった。少し進んだ先でまた詰まって今日は終了。

本に書いてあるものと論文に書いてあるもので定義に食い違いがあっておかしいということを発見し、指摘した。来週に持ち越し。

週記(2023/01/09-2023/01/15) - kotatsugameの日記

それから自分の発表の後半。昨日新たに用意した分だが、特筆することもなく1時間で話し終えてしまった。これで今日は終了、解散!かと思ったら博士課程の方が黒板に何やら書き始められ、セミナー続行。博士課程の方を中心に途中学食で夕食を摂りつつ午後8時くらいまでやっていた。発表というより証明をつけるのがメインで、自分は次の性質を示した。

積分布関数F(x)に対しその逆関数F^-:(0,1)\longrightarrow\mathbb{R}F^-(y)=\inf\{x\mid F(x)\ge y\}と定義したとき、これは左連続になる。0\lt y\lt 1\varepsilon\gt 0が与えられたときに\delta\gt 0であって\max(y-\delta,0)\lt \forall y'\lt y.(F^-(y)-F^-(y')\lt\varepsilon)を真とするようなものを見つければよく、具体的に構成できる。

z=F^-(y)-\varepsilon/2としたときF(z)\lt yなので\delta=y-F(z)とできる。するとy-\delta\lt y'\Leftrightarrow y'\gt F(z)Fの単調増加性からF^-(y')\ge zが言えて、F^-(y)-F^-(y')\le F^-(y)-z=\varepsilon/2\lt\varepsilonが成立する。

帰宅してすぐにもう一度外出した。ゲーセンに向かう。以下のような理由で今日明日中に16クレ程度プレイする必要があるのだ。思ったよりセミナーが長引いてしまったが、まだギリギリ今日で終わらせられると判断した。

チュウニズムデュエルがまだ結構残っており、具体的には02/08までに35クレ程度プレイする必要がある。

週記(2023/01/30-2023/02/05) - kotatsugameの日記

今日も先週と同様14+をいくつか詰めた。新規にSSS+を三つ、また「GOLDEN RULE」のAJを出した。今日はラストが押せる日だったが、AJ間際は焦って擦らなくてもよいところを擦ってしまった。ギリギリセーフ。それで赤が増えたのが気になるとは言え、1個や2個気にするような精度ではない。

閉店まで粘ってギリギリでデュエルを終わらせた。

立ち食いそばを食べて帰宅。何もする気になれず長い間TLを眺めていたが、何とかシャワーを浴びて布団に入った。少しなろうを読んで午前4時くらいに寝落ち。

02/08(水)

午後3時くらいに目を覚まし、なろうを読みながらAmazonの配達を待っていた。先週日曜日に注文した本棚が今日届く予定。玄関先に置かれると持ち運べないので、是が非でも部屋の中まで入れてもらいたかった。無事受け取り、午後4時半くらいに寝た。

午後7時起床。すぐに本棚の組み立てを開始した。3時間くらいかけてとりあえず形にはなった。

上半分と下半分をそれぞれ組み立て、途中で合体させる。ここはどう考えても二人必要そうに見えるし実際二人以上で作業するよう説明書に書かれてもいるが、一人でもなんとかなった。つまり上半分を持ち上げることさえできればよいのだ。そんなにガッシリした本棚ではないようで思ったより軽かった。

合体にはカムロックなるボルトとナットの組み合わせが使われていた。ユルユルなように見えて締めてみると案外しっかりしている。興味深い部品だった。

ツイートの写真からさらに棚板を入れたところで時間になり、Codechef February Cook-Off 2023 div.1に出た。2022/09/23以来ということで久しぶりのCodechef div.1だ。

https://www.codechef.com/COOK144A

TAKENOTLESSはAの最大値がちょうど一つなら先手勝ちというところから考察を進めていった。同様に最大値が奇数個あれば先手勝ちだが、偶数個ある場合どうなるか考えてみると、どうやら2番目に大きな値に判定が移るらしい。まとめるとどれかの数が奇数個存在するのが先手勝ちの必要十分条件になった。

DUMBLEDOREはans_{i,i}から降順に考えていくとわかりやすかった。ans_{i,i}だけかかってしまう人を適当に一人選び、その人のタスクでT最大のものを1個取り除いた状態がans_{i,i-1}を達成する。以下同様。これは逆に、タスクT_{i_1},\dots,T_{i_k}を持っている人はans=T_{i_1},T_{i_1}+T_{i_2},\dots,T_{i_1}+\dots+T_{i_k}となる瞬間がそれぞれ1回ずつあるということになって、差分更新が非常に簡単に書ける。半信半疑で提出したら通った。

MINIMIZESINはダメダメだった。累積和\bmod{180}を考えるまでは良かったが、その後bitsetを遅延セグ木に乗せようとして1時間ほど溶かしてしまった。気合いを入れると値のインデックスの取得もできるように思ったのだ。書き上げるも全然うまく動かず、ここでようやく正気に戻った。

鳩ノ巣原理から区間の長さが180以上なら必ず累積和2か所の値が一致し、その間の区間和が180の倍数になる。そういう区間が見つかるまで探索して、見つからなければあきらめて\bmod{180}後の最小値を調べる。どちらもクエリあたり180の定数倍ステップの計算しかしないので間に合う。

POTTERCYCLESはひたすら実験するも解けず、3完46位。レートは2889→2855(-34)。コンテスト後に以下のツイートを見ながらupsolveした。

何も考えずfunctional graphのほうに進んでしまい、置換の符号を考えるのを完全に忘れていた。長さ奇数のサイクル1個と1頂点がたくさんならサイクルを逆順に辿れば2手でできることは分かっていたが、それを作ろうという発想にならなかった。揃えるのに5手以上必要なケースもあると思い、最短手数を必死に探していた。

言われてみれば、サイクルを順に辿った列をつなぎ合わせてソートするとサイクルごとに1頂点を残して全部合うし、残ったものはそれ自体が一つの大きなサイクルになる。そして置換の符号を調整しておけば、そのサイクルの長さは必ず奇数になるのだ。ここまで高々2手なのでこの後の2手と合わせ制約ピッタリになる。

コンテスト後は新しい本棚に本を入れていた。買った順番でバラバラに入っている状態が好みだが、さすがに使いづらいのでソートした。もっぱら配置決めに時間を使い、朝方にようやく完成した。部屋にある文庫サイズのライトノベルは全部ここに入れてある。古い本棚には大きなサイズの本と一般の文庫が残された。

古い本棚がかなり空いたので別の用途に使いたい。とりあえず棚板をずらそう、と思ったら1本ダボが抜けず非常に苦労した。指で必死につまんで引っ張っていたが、ただただ爪が食い込んで痛いばかり。まったく抜ける気配がないため、明日大家さんからペンチを借りようと思う。

明日は家飲みで1日潰れる予定だから、金曜日の1on1に向けてインターンの進捗を産んでおく必要がある。腰が重くずっとなろうを読んでウダウダしていたが何とか午前10時前に完成した。布団に入ってまたなろうを読み、午前11時過ぎ就寝。

02/09(木)

午後3時過ぎ起床。筋肉痛で足腰が満遍なく痛いし、ダボをつまんだ指先も痛い。

大家さんに連絡してペンチを貸していただいた。昨日の苦労が何だったのかと思うくらい簡単に抜け、拍子も抜けた。

その後外出。ホスフィンと合流し、微妙な時間の食事を摂ってドンキで買い物して帰宅した。家飲み開始。

今日はホスフィンが持ってきた日本酒3本だった。どれも宮城県のお酒で、飲み比べしようとのこと。日本酒の良さを知ろうと無理やり口内に留めて味わったら苦さを感じるばかりだったが、ホスフィンに香りや喉越しなど味以外の観点も教えてもらって、無理に味わわないようにしたら幾分か飲みやすくなった。2本まではそのまま飲み、最後の1本はジュースで割って飲んでいた。

お酒を飲んでいる間、動画は見ずにずっとボードゲームをしていた。新しく買ったものは「バトルライン」「ヨメン」「Blade Rondo」。それぞれ感想を書く。

バトルライン」は9並列でポーカーみたいなことをするゲーム。結構楽しかった。「偵察」という戦術カードの効果には「部隊・戦術カードの山札から好きな組み合わせで3枚のカードを手札に加えます。……」と書かれている。自分とホスフィンはこれを「自由に3枚サーチできる」と解釈しプレイしていた。あまりに強すぎて使った側が必勝のゲームになり、さすがに変だと思って調べたところ、山札の上から合計3枚ドローするカードだと判明した。

「ヨメン」は前回プレイした「タギロン」の続編みたいな位置付けのゲームらしい。立体配置を考える必要があるし質問の自由度も高くてより難しくなっている。ところで自分の感じる難しさと面白さにはあまり関係がない。2回くらいしかプレイしなかったが、あまり好きではないと感じた。

「Blade Rondo」は限られたカードプールから7枚ずつ手札を持って対戦するカードゲーム。一目見てイラストに惚れ込んだ。実際にプレイしても非常に面白かったので、総合してこれまで購入したボドゲの中では一番のお気に入りとなった。同シリーズの後継作品があと四つあるらしい。今すぐにでも全部買ってしまいたいが、家飲みの度に一つ二つ買ってじっくり楽しみたい気持ちもある。

自分は「フレアビスカス」とレスポンスカード・使い切りのカードで手札を固め、中盤から4コスで6ダメージの魔法攻撃を繰り返す戦法をよく使っていた。ホスフィンは「マナティックルピナス」と「トリビュートリリィ」で一気にダメージを稼ぐことが多かったように思う。二人ともプレイするうちに物理攻撃をあまり使わなくなっていった。

www.dominagames.com

お茶を挟まずにお酒ばかり飲んでいたのが悪かったのだろう、午前2時くらいに急激に吐き気が来た。しかし嘔吐の経験がないので便器を前にしても何も出せず、それはそれでつらい。少し持ち直したところで布団に倒れこみ、寝た。

02/10(金)

午前6時過ぎに意識を取り戻した。ホスフィンも仮眠していたらしく、まだ部屋にいた。自分が潰れた後も飲んでいたのかお酒が全部なくなっていてびっくりした。まさか二人で飲み切ってしまうとは思わなかった。少し片づけをして、ホスフィンが帰るのを見送り、また寝た。

午後1時過ぎ起床。今セメスターで応用数理総論を担当されていた先生の最終講義にオンラインで参加しつつ、届いていた新春TCB2023の賞品を開封した。

2021年の新春TCBでもほぼ同じ機種を貰っておりこれで二つ目。HHKBも2台、PCも2台あるのでバランスがよい。そして、このキーボードとマウスはすべて競プロで得た賞品となる。

週記(2023/01/23-2023/01/29) - kotatsugameの日記

1時間程度で終了し直後から1on1。通常の進捗報告やタスク設定のほかに、サーバを立ててプログラムを動かすことになったのでその話もした。サーバの設定をやらせてもらえることになり、見守って頂きながらしばらく格闘していたが、全然うまくいかない。最終的には既存のサーバの設定ファイルをほぼコピペしてくるような形になった。それでも良い経験になったと思う。今のところは期待通りの挙動をしている。

結構長引いて午後5時くらいに終了。今日はこの後競プロサークルの追いコンがあるので、シャワーを浴びて外に出た。雪がかなり降っている。この時点ですでに遅刻が確定しており、さらにゆうちょ銀行を探すのに手間取って集合時刻から20分ほど遅れてしまった。直接お店に向かって合流した。

今日は武屋食堂というコロナ禍前に確定新歓でよく使っていたお店で飲み放題付きのコース。出てきた料理はすべて写真を撮り、以下のツイートのツリーにまとめてある。

午後9時過ぎに店を出て二次会でカラオケに移動した。ボドゲを持ってきていたので1戦だけ行ったが、会話が不可能なのでびっくりするくらい楽しくない。その後は普通に歌を歌って楽しんだ。

自分が歌ったのは「大地讃頌」「君の知らない物語」「フォニイ」。大地讃頌は音もリズムも覚えておらず何もできなかった。フォニイはその辺りちゃんと覚えてこそいるものの、シンプルに難しくてボロボロだった。君の知らない物語だけは辛うじてまともに歌えたと思う。

午後11時に解散し、閉店間際のゲーセンで1クレだけ遊んで帰宅。昨日空けた酒瓶等をゴミ捨て場に出した後シャワーを浴びて、それからずっと日記を書いていた。午前8時前に就寝。

02/11(土)

午後2時ちょっと前になんとか起床。すぐUniversal Cup 3回目に参加した。今日のセットはPoland由来らしい。

The 2022 Polish Collegiate Programming Contest (AMPPZ 2022) - Dashboard - Contest - QOJ.ac

チームでCGDAMKBELを解いた。自分はCDABEの実装を担当した。

先頭から順番に読む担当だったので最初にA問題を開いたが、TL 42secと書いてあって目を疑った。ほかの問題もかなりダイナミックにTL・MLが変更されている。感想戦の時に聞いた話ではこれはPoland典型で、ほかのセットもそんな感じだったようだ。

コンテスト開始早々にたくさん問題が通され始めた。そのうちCGDAはポンポンと通って、一瞬一位になった瞬間があったような気もする。Cは自明。Gはかっつさん。Dは親子で部分木のサイズを比較し答えにならないdに対してimos法でチェックする。これがすぐ思いつけたのは良かったし少し面白いとも感じた。Aはa+b+c\le 5で全探索し、見つからなかったら(a,b,c)=(0,0,6)が必ず答えになる。TL 42secにビビっていたがなんて事のない簡単枠だった。

ここから少し時間が空いた。通されていたのはMKBIで、Mはぷらさんが、Kはかっつさんが通した。自分はその間にBとIを読み、多く解かれていたIを考えていた。

k+1個以下の連続部分列に分けてそれぞれの転倒数の総和を最小化する問題に帰着できる。ここでkの制約を忘れてしまい、解けたものと思って実装に割り込んだ。サンプルが合わず正気に戻った。n\times kのテーブルをin-placeに更新していくことを考えると、行に対する加算と列の最小値取得クエリに対応できればよい。しかしそのようなデータ構造を知らない。

行に対する加算について、上の行ほど大きな値が加わるという事実から何かできそう。例えば列ごとに見ると三分探索できるんじゃないかとか、最小値を取る行は単調増加じゃないかとか。しかし詳しいことはわからなかった。

Bの考察に入っていたぷらさんに呼ばれたので見に行った。両端とp最大はかならず開業すべきらしい。これを発展させると、開業させるpの列は最大値までが単調増加、そこから単調減少になる。対称性から単調増加の部分だけ考察すればよい。

p_i\le p_j\le p_kがこの順で開業しているなら、[i,k]のみを考えたときの収益は(p_i+p_j)(j-i)+(p_j+p_k)(k-j)となる。p_jの開業を取りやめた場合は(p_i+p_k)(k-i)となる。前者が後者より大きいという式を立てて整理すると、(p_j-p_i)/(j-i)\gt(p_k-p_j)/(k-j)となった。

実はこれは(i,p_i),(j,p_j),(k,p_k)という3点の並びが上に凸となることを表す。ここで凸包を取るアイディアが思い浮かんだ。詳しい証明はできないもののいかにもそれっぽそう。ぷらさんは凸包の実装に自信がないということで、自分が奪い取って書いた。出したら通ってラッキー。

ぷらさんにIの考察を説明し、それっぽいという同意が得られたので実装してもらい自分はEに進んだ。TL 30secでML 8MBという意味不明な問題。最初に作れるのは2x-y2y-xのみだから、片方しか作れないケース、つまり2x-y\le 0のケースを考えた。

実験するとk\in\mathbb{Z}_{\ge 0}に対して(k+1)y-kxという形の数しか作れないことがわかり、ここから条件がx\mid yと出る。個数を式で書けば\sum_{x=1}^n(\lfloor n/x\rfloor-1)で、商列挙でカウントできる。

次は2x-y\gt 0のケースについて。d=y-xと置いてこちらも実験するとk\in\mathbb{Z}に対してx+kdという形の数のみが全部作れると分かった。正確には正である必要もある。ここからd\mid xが条件だと思い込んでしまい、割り込んで実装した。当然サンプルが合わない。

g=\gcd(x,y)と置くとx\equiv g\pmod dが条件。gとその倍数dを固定したとき、求めるペア(x,y)=(x,x+d)\lfloor (n-g-d)/d\rfloor個ある。d=kgと置くと1\le k\le (n-g)/gに対する\lfloor (n-g-d)/d\rfloor=\lfloor\lfloor (n-g)/g\rfloor/k\rfloor-1の総和が求めたいものとなった。

よく見るとn\leftarrow\lfloor (n-g)/g\rfloorとした上で2x-y\le 0のケースの個数を求めたのと同じ形をしているが、別に再帰的に解くわけではなく、ここでも商列挙をしてしまえば終わり。しかし試すと間に合わない。メモリ制限ギリギリのn\le 1.5\times 10^6まで前計算したら通った。この前計算も愚直にやると間に合わないので、倍数列挙で値の差分を計算した後累積和を取って求めている。

後から聞いた話では切り捨て除算を整数ではなく浮動小数点数で行うと速いらしい。今の制約なら誤差も出ないようだ。これでO(n^{3/4})が通るとの話。しかし自分の解法もちゃんと解析すると同じ計算量のはずなのに、試してみてもやっぱり通らなかった。商列挙を一つのループにまとめようとすると、平方根で処理を分けるより割り算の回数が増えてしまうので、その辺りが悪いのだろう。

素数カウント( $\mathrm{O}(\frac{N^{\frac{3}{4}}}{\log N})$・高速化版) | Nyaan’s Library

Lはかっつさんが単独で通した。Iはぷらさんといろいろ試していたものの上に書いていたことがすべてうまくいかず、結局通らなかった。9完71位。

感想戦。Gは泥棒の移動を無視して捕まるまでの時間を二分探索で求めるらしい。非常に頭が良いと感じた。Mはコンテスト中に自分もちょっと考えたが、ぷらさんによって後ろから見るというアイディアが出た段階で離れた。実際それでうまくいくようだ。復元は敵かどうかのフラグを下ろしながら見ていくと簡単そう。

Kは古代のARCのちょっとした一般化だったとのことで、ひたすら面倒そうなので通してもらえて助かったという感想。Lは必要条件を集めたら十分条件になっていたようだ。構築が重み降順でよいのはエスパーだったそうだが、感想戦の時に示すことができた。手数が多そうなのにほぼ最後までしっかり詰めているの偉すぎるという気持ちに。

C - 五目並べチェッカー

自分のEの説明が嫌になるくらいへなちょこで心残り。ポイントは\lfloor (n-g)/(kg)\rfloor=\lfloor\lfloor (n-g)/g\rfloor/k\rfloorと分解したところだと思っていたので、それを強調しようとしたが、導入する変数がちょっと多くて話しながら迷子になりかけた。するとフィラーも多くなるし、頻繁に人の理解を確認したくなって、説明が途切れ途切れになってしまう。感想戦の前に、日記にそのまま書けるくらいにはまとめておきたい。

午後8時過ぎ解散。手元を撮影する準備を整えて午後9時からABC289に出た。先週は机の上にラノベを積みその上にWebカメラを置いていたが、スマホアームが使えることに気づいた。

Sky Inc, Programming Contest 2023(AtCoder Beginner Contest 289) - AtCoder

Aは見た瞬間tr 01 10。Bは問題文がいかついがレ点の説明をしているだけだった。連結成分の取得は毎回右側に伸ばせるだけ伸ばせばよい。Cはbit全探索。集合の個数をMではなくNにしていて1WA。DはN\le 10に気づけば終わり。Eは二人がいる頂点をペアで持つdpを書くと、状態数O(N^2)、遷移が合計O(M^2)なので間に合う。

Fは(x,y)から(X_1,Y_1)(X_2,Y_2)で2回操作すると(x+2(X_2-X_1),y+2(Y_2-Y_1))に移動する。このことからa\lt bc\lt dなら各座標\pm 2ずつ調整することが可能で、座標の偶奇さえ合っていればどこにでも行けると分かった。そもそも操作で座標の偶奇は変化しないので、これは必要条件でもある。a=bまたはc=dの場合は最初に(a,c)で操作するかどうか試せばよい。操作回数の偶奇を両方試していることに相当する。

Gは商品ごとに独立に解いてよい。Pを中途半端にする理由はないので、P=B_i+Cとなるiが存在するべき。このときBが昇順ソートされているとすると、iが0-indexedとして購入者はN-i人だから、売り上げは(N-i)(B_i+C)=(N-i)B_i+NC-iCと計算できる。NCは定数項なので(N-i)B_i-iCというCについての一次関数を最大化する問題になった。

ライブラリを窃盗すればすぐ通せるが、せっかく動画を撮っているので自分で実装することにした。まず傾きの単調性を利用して最大値を取りうる直線だけ記録。Cごとにその上で三分探索する方法は本当に正しく求まるか自信がなかったので、Cもソートしてどんどん見る直線をずらすように実装した。

Exは何もわからず。3人の距離を2変数において変化を確かめても綺麗な形にならなかった。2変数の形式的べき級数に書き直してもみたが、そこから先は経験がない。

7完30位。Aはコンテスト開始9秒でFAを取れた。久しぶりのFAだし一桁秒でのACはこれまでで初めてのはず。

コードゴルフ。AはFAの提出がそのまま最短。Bはstackを持って出力する方法があるらしく、このstackを関数の再帰で表現した以下のPerlコードが美しく短いと感じる。自分のコードではないし縮みもしない。CはRuby再帰。以降は手付かず。

atcoder.jp

午後11時からTROC #31に出た。

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

AはS+T。Bは最も近いところに貪欲に移動してよい。Cはf=0となるのが\lfloor N/M\rfloor人で、次に小さいf1/Mなので、\lfloor N/M\rfloor/N\ge 1/Mが必要。ここから必要条件M\mid Nが出て、これが十分であることもほぼ明らか。

DはWをいくつか選びデクリメントによってdistinctにして、対応するPの総和を最大化する問題。Wの降順に見てPを優先度付きキューで管理し、都度最大値を取得していけばよい。

Eはそれぞれの辺についてそれがessentialとなる座り方を数える。つまり、その辺を取り除いてできる二つの連結成分から人が交互に座る場合の数だ。Kが奇数の場合はそもそもありえないので答えは0。偶数の場合は各連結成分からK/2人ずつ選んで並べる方法なので、簡単なcombinationで書ける。

Fはそれぞれが次に着地する柱の番号を持つN^2状態のdp。同じ番号の柱に着地するのはN状態しかないので、それぞれO(N)かけてジャンプ距離の候補を列挙し一致するものを採用しても間に合う。そうでない状態はより小さい番号の柱にいるキャラクターをジャンプさせる。このときより大きい番号の柱ならどこにでも着地させられるので行または列全体への遷移となり、行全体・列全体を表す変数に配って毎回貰うようにすれば定数時間で実現できる。

Gは累積XORを取って桁ごとに考える。先頭の0も含めたN+1個のうち2^kのbitが立っているものをc個とすると、Sにはc(N+1-c)\times 2^kだけ寄与する。kごとに各cを達成する場合の数を求め、先ほどの寄与をインデックスにしてすべてのkについて畳み込めばよい。場合の数は多項式を考えて求めることにした。

直前の累積XORでbitが立っているかどうかも必要なので、多項式は二つ持つ。よってAを一つずつ見ていく遷移が1次式を要素に持つ2\times 2行列になる。そのような行列全体の積を半分ずつに分けて計算していくコードを書いたら通った。そもそも寄与の値は0の次に小さいのがc=1,NのときのN\times 2^kで、これがS以下にならないならc=0だけ確認すればよい。よってNが小さいか計算すべきkが少なくなって、思ったより高速。

Hは解けず。場合の数を微調整しながら進んでいくdpを考えていたが、思ったより必要な情報が多く間に合いそうな形にまとめきれなかった。

Gまではかなり良く7完最速で6位、2771→2799(+28)。Bの元ネタがおそらくチュウニズムでびっくりした。

ABCの動画を公開した。撮ったものをそのままアップロードしてYouTube上で前後を切り落としたが、アップロード後の動画処理を待った後さらに切り落とした後にも同じくらいの待ち時間が発生して大変だった。横着せず手元で完成させたほうがいい。

動画の途中で「蟻本の式が間違っている」ということを口走ってしまったが、最後のほうでちゃんとチェックして正しいことを確認している。悪影響を与えるといけないため、このことは概要欄にも記載しておいた。

www.youtube.com

朝まで日記を書いていた。午前9時頃布団に入り、1時間ほどラノベを読んで就寝。

02/12(日)

午後5時起床。

応用数理総論の期末レポートの評価が出ていた。なんと満点!以前日記で言及した以下の部分は順序数の足し算に関する話で、具体的に書くと、より小さい順序数の足し算に帰着した後適当に「帰納的に示される」と述べて終わったのだった。解説を読んでこれがいわゆる超限帰納法だったことを知った。

かなりそれっぽい式変形を行えたがその後のステップがわからない。もう元気がないので適当にまとめてレポートを完成させてしまった。

週記(2023/01/30-2023/02/05) - kotatsugameの日記

素数が無限個存在する」、つまり「どんな数にもそれより大きな素数が存在する」ことを表す\Pi_1文を書く問題の解説がよくわからなかった。xより大きな素数を見つけるのに上からx!+1で押さえると広義の\Pi_1文で、ベルトラン=チェビシェフの定理を使って2x+2x=0を考慮)で押さえると厳密な\Pi_1文になるらしい。そもそも広義云々というのは講義に出てきていないし違いがよくわからない。どちらも再帰的に計算できる上界という意味で変わりないと感じている。

午後5時半からCF #852 div.2に出た。

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

Aはまずm+1キロごとに貪欲に買って、最後に余った部分を調整すればよい。変なケースがあると思って少し考え込んだ。

Bはlocal maximumとlocal minimumを一つずつ作るのにその差の2倍だけ長さが必要になる感じなので、それぞれxyだけ用意すれば十分。具体的にはx,x-1,\dots,y+1,y,y+1,\dots,x-1でよい。制約にx-yの最大値が書かれていないように見えて、出すのは勇気を要した。Outputの欄に書いてある\sum n\le 2\times 10^5がそういう意味だったのだろう。

Cは各lに対するrの最小値、また各rに対するlの最大値が求まる。これを使って一度数え上げ問題を解いてしまった。実装まで終えてからサンプルを見て間違いに気づいたが、修正は簡単だった。

Dは順列に対してありうるMEXとそれを達成するのに必要な区間の制約が列挙できるので、両方の順列に対して計算しMEXを全探索することで答えが求まる。

Eで3WAした後、順位表を見てたくさん解かれていたFに進んだ。何も考えずMoを書いたらクエリ処理にsetが必要で当然TLE。高速化も不可能だったので別の方針を考えた。区間rを昇順に見ることを考えると、毎回すべてのl\lt rに対し|a_l-a_r|を計算してセグ木のインデックスlに乗せることで答えが求められる。

ここで特に、lを降順に見ている場合はこれまで計算した値より|a_l-a_r|が小さくなるものしか新たに計算する必要がない。aをインデックスとして位置をセグ木に乗せ、区間MAXを取得することで次に計算するべきlが高速に手に入る。今aは順列だから、実はこのようにした場合考えるべき(l,r)のペアが十分少ないのではないかと考えた。証明はできなかったがまずいケースも思いつかなかい。提出したら通った。

E。m人満足させるとき達成可能なkの最大値を求められればよい。満足する人はaが小さいほうからm人としてよい。同じ本を読んだ人の中に満足した人としていない人が混在する場合を忘れて同じ本を読んだ人は全員満足させようとしていたのが3WAの原因だが、まずその実装を説明する。

aをソートしておく。m人満足させる、特にa_mに対応する人を満足させようとしたとき、a_{m-a_m+1},\dots,a_mに同じ本を読ませるのが今の場合最適で、問題はm-a_mのケースに帰着される。人数が多い分には問題ないのでこの値はm-a_m以下なら何でもよい。いずれにしてもm\ge a_mならm人全員を満足させられて、残りのn-m人はバラバラの本を読ませておくとkを最大化できる。

忘れていたケースを付け加える。満足した人としていない人が混在する場合、そのような本は高々1種類で、そこで満足した人のaはできる限り大きくするべきと分かった。よって先ほどの計算をおおむね流用できる。m人を満足させるときのkの最大値としては、a_1,\dots,a_mが読む本の種類数に加えて残りn-m人が読むバラバラの本がある。

これを発展させてi\gt m)人を満足させてみる。バラバラの本を読んでいる人のうちa_i人に同じ本を読ませてa_{m+1},\dots,a_iを満足させるのが良いだろう。n-m\ge a_ii-m\le a_iが条件として必要で、種類数は-a_i+1される。種類数の差分が一定なので、条件を満たすmから種類数最大のものを探すことで求める新たな種類数が得られる。以上のことをセグ木で実装したらすんなり通った。

全完22位。Fはa_la_rの大小関係を固定すると「これまで計算した値より|a_l-a_r|が小さくなる」という部分がより強く「半分未満になる」と言えるらしい。この事実には順列という条件は特に使われていない。

食事してAGCまで落ち着かない時間を過ごした。今回も録画する準備を整え、午後9時からAGC061。

AtCoder Grand Contest 061 - AtCoder

Aは置換を考えてもよくわからなかったがどんなswapが行われるか観察するとかなり見通しが良くなった。操作する区間の幅が2増えるごとに大規模なキャンセルが起こり、1と2、3と4のようなペアの間でしか意味のあるswapが発生しないらしい。このあたりで実験コードを書いて確かめた。

Nが偶数の場合はこれで答えが2通りになるし、奇数の場合も4通りには収まりそう。だから全探索してチェックするという方針が取れる。あとはNが偶数のときに特定の2数がswapされるか高速に判定できればよい。

どこでswapが行われるかをN\le 16くらいまで手で確かめると、シェルピンスキーのギャスケットが見えてきた。そういえば「上の段をずらして重ね合わせる」のは二項係数の計算だったから、その偶奇がこういう模様になっているのだ。巨大な二項係数の偶奇はLucasの定理で一発。\binom n knkを丁寧に確認して実装し、先ほど書いた実験コードで確かめたところN\le 33までの正答が確かめられた。

提出して無事AC。30分ちょっとかかってしまった。

この後Bに1時間、Cに残りの時間を費やしたがどちらも何もわからなかった。1完172位でパフォーマンス2489、レートは2875→2842(-33)。順位がちょうど100位となってギリギリ銅冠は剥奪されなかった。せっかく撮った録画だがさすがに情けなさすぎるため削除した。

Bは手で試してN=3,4の場合の構築を見つけ、N=5で力尽きた。コンテスト後のTLを眺めていると、N\times(N+1)のマス目を書いて1マス1辺に対応させその上でジグザグの線を描いている人が多く、自分も試してみるとN奇数の場合の構築が分かってしまった。残念。N偶数は試していない。

Cは解いた人のツイートなどを少し読んで、dpを微修正しながら進んでいくというコンテスト中に頑張っていた方針が間違っていなかったことを確認した。しかし改めて考えてみても本当に何もわからなかった。まさに手も足も出ない問題。

ラノベ「隣の席の美少女をナンパから助けたら、なぜかクラス委員を一緒にやることになった件」を読了。こんなタイトルをしていて、実は主人公は勇者として異世界を救った帰りという設定。異世界で手に入れたスキルやコミュ力で青春を無双する話は好みだと思って読んだ。しかし微妙だった。主人公が目立つという好みのシーンはちゃんと用意されていたが、そういう加点要素より主人公のセリフ回しとか陰キャ時代の唯一の友達が登場だけしてほとんどクローズアップされなかったところとか、減点要素が大きいと感じてしまった。

AGCがあまりにも不完全燃焼だったので、出る予定のなかったJOI本選のオープンコンテストに午前3時から4時間で参加した。

第22回日本情報オリンピック 本選 オンラインコンテスト

このコンテストの言及解禁は月曜日の午後7時だが、それまでに週記は投稿できないだろうからここに全部書いておく。結果をまとめておくと、1・2・4問目が満点、3問目が86点、5問目が62点で合計448点だった。

1問目は同じ色の連続する碁石をまとめて保存しておくとよい。色を表す数値が過剰に大きいのは嫌がらせ要素か。

2問目は結構難しかったし結局よくわからないまま通した。住人iが本を手に入れれば住人jも買う、という関係をi\rightarrow jと書く。各jについてi\rightarrow jを満たすiのうち数直線上で最も近いiを左右それぞれ探して実際にi\rightarrow jの辺を張り、そうして作った有向グラフをSCCして入次数が0の強連結成分数を答えたら通った。

日記を書いているときに整理した結果、背景には|X_i-X_j|\le E_i-E_j\land|X_j-X_k|\le E_j-E_kならば|X_i-X_k|\le E_i-E_k、つまりi\rightarrow jかつj\rightarrow kならばi\rightarrow kが成り立つことがあると分かった。i\rightarrow jという辺を全部張って上と同じことをすれば少なくとも答えが求まる。

なぜ上のような辺だけしか考えなくてよかったのかはよくわからない。左右それぞれ辺が存在するならそのうち1本張られていれば十分だったのかもしれないと考えている。

3問目は謎。ハンコを押す度、それによって白く塗られたマスのうちまだ訪れていないマスのみを高速に列挙できれば解ける。

例えばこれは矩形領域三つの和だから、2次元累積和を使うとある程度まとめてO(RC)で求まる。BFSするのとハンコを1回押すのを答えが見つかるまで交互に繰り返すと、毎回の計算量がO(RC)で、答えの最大値がO(C/N)となるから計算量はO(RC^2/N)

あるいは行方向だけ全列挙して列方向はsetなりbitsetなりを使うとよいかもしれない。1マス当たりO(N)行見る必要があるのでO(RCN)と見積もった。正確にはマス目の探索でもっとかかりそうだがよくわからない。

この時点でO(\min(RC^2/N,RCN))が達成できたと考えた。N\le R\le Cなので実はO(RC^{3/2})ではなくO(RC^{4/3})になっているはず。ギリギリ間に合うと信じて提出したら小課題6以降が通らず67点だった。5問目まで取り組んだ後戻ってきて格闘したら小課題6は何とか通ったが、それで終わりだった。

4問目は簡単だった。最も高いタワーに障害物を置くと、そのタワーを取り除いた後の連結成分のどれかに移動し、以降はその連結成分内でしか動けない。だから逆に、タワーの高さの昇順に見て行って連結成分をマージしながら解くことができる。

マージの際、移動する連結成分は全探索できる。そして連結成分の中で次に移動するのは最も高いタワーだとしても損しない。そのタワーに移動しないようにするためには障害物を置いておく必要があり、以降の動きは一度訪れてからでも全く同じことができる。

UFで連結成分と同時に最も高いタワーを管理し、dpした。木の上の距離をO(N)回求める必要があるので、LCAを使って毎回O(\log N)かけて処理した。

5問目はさすがに難しくてほとんど何もわからなかった。実験するとスタート位置の左にあるRと右にあるBの個数が重要で、ボールが取り除かれた後は適当な範囲が一気にRまたはBになっていると分かった。つまり区間に対するRBのカウントと、それを見て二分探索で求めた区間への一様な代入でボタンを押すシミュレーションが書ける。遅延セグ木でO(QM\log N)となり、小課題3まで通る。

小課題4と5は全く別方針。この二つはどちらもCの左からいくつかがR、残りがBという形をしている。こういう分割はどこにボールを置いたとしてもずっと成り立ち続けるようだ。境目を問題文と同様tとし丁寧に実験してみると、タイルAの上にボールが置かれたとして、t\lt Aならt\leftarrow(t+A+1)\bmod{(N+1)}t\ge Aならt\leftarrow(t+A)\bmod{(N+1)}となると分かった。

平方分割してブロックごとにtの変化を全通り求めておくことにした。この計算はtO(N)通り試さないといけないように見えるが、ある区間に対しては常に全く同じ増分となるため、その区間を検出しながら繰り返すことでそこそこ高速に全て求まる。ブロックサイズをBとすれば区間はおそらくO(B)個となるはず。よって前計算O(M/B\times(B^2+N))、クエリ当たりO(B+M/B)で答えが出る。

最初の提出は小課題4しか通らなかったが、ランダムケースの速度を見ながらBを大きめの1000に設定したら小課題5まで通った。

その後は日記を書いていた。午前10時くらいに切り上げて布団に入り、なろうを開いたところで寝落ちしたらしい。

週記(2023/01/30-2023/02/05)

01/30(月)

午後2時に一瞬起きて修論発表会のZoomに接続した。もともと可能なら参加するようにと指導教員の先生に言われていて、特にこの時間帯は基礎論の発表だったから無理して起きてみた。しかしやはり無理だったようで、接続はそのまま放置して布団に戻り二度寝した。

次に午後4時半ちょっと前に起床しインターン先定例会に参加した。先週は集中講義を理由に何も稼働していないが、そもそも先週の進捗報告にも出席していないため、先々週少しばかりコードを修正した分の報告が残っていたのでそれを発表。

勉強会は二値分類の精度指標の話だった。F値という指標は二つの指標の調和平均で定められておりなんだか複雑そうな形をしているなと思ったら、式変形でそこそこ綺麗な分数になってびっくりした。

質疑応答が活発で終了時刻は午後7時半になった。おそらくこれで1月中の稼働は最後だろう。今月は年始や集中講義で2週間くらい何もしていなかったため、インターンを初めてから断トツで稼働時間の短い月となった。

夜中まで週記を書いていた。ABCの部分を書いているときに最短コードをチェックしていると、A問題が縮んでいるのに気付いた。改行を含めるとForが4文字、Againstが8文字だから、文字数の総和と6Nを比較することで判定できるらしい。考えもしなかった。

atcoder.jp

午後11時くらいになってようやく投稿。今週も当然のように校閲が終わっていない。

TUPC2022の情報が公開されていた。今年はAtCoderで開催されるし、大学の教室を借りてオンサイト会場も用意される。どちらも交渉ややり取りはサークルの面々が頑張ってくれた。自分は何もやっていない。

実は明日も修論発表会があって、その影響でセミナーが水曜日にずれているから準備も明日でよい。疲れ果てて布団に突っ伏し、日付が変わったくらいに寝落ちした。

01/31(火)

午前4時から午前11時くらいまで起きてなろうを読んでいた。また午後3時くらいに頭の痒みで起きて、急いでシャワーを浴びた記憶がある。

午後8時起床。1時間ちょっとハーメルンを読んで布団から脱出した。ABC283の賞品でアマギフ2万円分が届いていた。

セミナー準備になかなか気持ちが向かず、かなり長い間YouTubeニコニコ動画カクヨムに時間を使っていたらしい。明日は平面グラフに入る予定で、定義とその直後にある補題をいくつかやるつもり。それらの補題は定義したすぐ後に書いてあるくらいだし簡単なものだろうと舐めてかかっていたのだ。

午前2時から開始したが、思ったより証明が長大でびっくり。内容も平面幾何の話が結構あって、直観に頼った議論になっていないか慎重に確認する必要があり時間がかかる。何とか完成したのが午前5時半だった。

シャワーを浴びて午前6時過ぎ就寝。

02/01(水)

午前9時半起床。セミナーのため大学に向かった。購買でパンを買ったりしていて10分ちょっと遅刻した。購買の開店とセミナー開始が同時なのは不便なので、今度スケジュールを改める機会があったら主張したい。

午前中は明後日に博論発表会を控える博士課程の方の発表練習だった。まず聞いて、それから質問を飛ばす役割。

これまで1年くらい一緒にセミナーをやってきて発表も何度も聞いているので、何をやっているかはある程度理解できる。一方そのために大した質問ができない。なぜなら今聞いて抱くような疑問はこれまでのセミナーで解決済みだからである。「この研究は何が嬉しいのか」「あなたの仕事はどう新しいのか」とかTwitterでよく見るようなことを知った顔で言うなんてもっとできるわけもなく、捻り出した質問を一つ二つ聞くだけで精一杯だった。

昼食は学食で、先生と同級生との3人で摂った。行き帰りの間に先週集中講義で休んだTAの話を聞いたが、今週は期末テストで忙しい人が多いらしく休講になったそうだ。来週以降は単純に授業日ではないので先週が最終回だったことになる。そこだけピンポイントで休んでしまったというのは少し残念。

同級生が3限と5限に講義を取っているらしいので、次のセミナーは4限の時間となった。これまでいた教室も別の講義で使われるようなので待ち時間は院生室でずっとなろうを読んでいた。暖房が入っていなかったためかなり寒かった。

4限になり発表。90分しか時間がないのを忘れ、終了時刻を決めない普段のような感覚で喋っていたら、用意した分が全然終わらなかった。平面グラフの定義のあたりを過剰にネットリ説明してしまったようだ。昨日頑張って準備した補題はその長大な証明を説明する時間などあるはずがなく、主張だけ確認して終了。

帰宅途中に川内キャンパスの生協に寄って予約していたラノベを受け取ったが、その10分程度の間に雨が降り出していた。空模様で遠からず降ることはわかっていたとは言え、こうも絶妙なタイミングだとちょっと悲しい。

午後5時過ぎに帰宅。ゲーセンに行きたいが疲れ果てて動けない。1月の読書記録を集計するなど今日のうちにやっておきたい作業を素早く終わらせて布団に倒れこんだ。

午後6時半から午後11時まで睡眠。起きてからCF #848 div.2に出た。

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

Aは操作をちょうど1回行うという条件を忘れて実装してしまい少し手間取った。しかも見切り発車で書き始めたら\pm 1の個数をそれぞれ数えるという面倒な実装方針を取ってしまった。

Bはちょっと難しかった。操作する必要がある場合、1\le i\lt mを選んでa_ia_{i+1}の位置を近づけるか遠ざけるかすることになる。近づけるほうはちょうどa_{i+1}a_iの直前に来るようにすればよく、必ず可能。一方遠ざけるほうは最大まで離してもどうにもならないことがあるのでチェックが必要。条件式に括弧を入れ忘れて1WAしたが、別のところを疑っていてバグの発見に時間がかかった。

Cはrを固定し、各lに対しa[l,r]=b[l,r]とするために必要なQを考えると、l=r\dots 1の順で単調に大きくなっていく高々11通りしかない。Qを全探索して(l,r)の組を数えておき、部分集合に渡る和を求めることで答えになる。ゼータ変換したが愚直でもよい制約。各rに対し最大のQに対するlを計算し忘れていて1WAした。

Dは文字が異なる位置の数を状態とした期待値dp。ループがあるが、dp_{i+1}dp_iの1次式で表すことでdp_nから順に計算できて、その後dp_0=0から順に具体的な値を確定させられる。

Eは部分木全体から作った基底を管理して全方位木dp。根を移動するとき元々の根にあった値を書き換えるのと、根から戻ってきたときに元の値を復元することに気を付ける。根自体の値がどうなるかよくわからなかったので、そういうケースはすべてのaを使った基底を求めて先に計算しておいた。

基底の実装はいわゆるnoshi基底を使った。これは基底の順番にも意味があるのだが、値の最大化を貪欲で行うために降順ソートする必要があると思って基底を求めるタイミングですでに降順ソートしてしまい壊れていた。実はもともとの順番で貪欲に取っても最大化できるようだ。

Fは木dp。部分木に対してそこにある値をすべてgの倍数にするために必要な最小の操作回数を持つ。gとしてはa_1の約数しか見なくてよいことを使うと十分高速。最初それに気づかず実装していて、pretestで1934msだったので出し直した。最初のコードはシステスで落ちるようなので助かった。

全完16位。序盤手間取ったりWAを出したりしていてちょっと残念。

TUPCのテスター作業を延々続け、午後1時前に就寝。

02/02(木)

午後7時起床。TwitterAPIが02/09から有料化されるということが話題になっていた。自分もTwitter botのatgolferを管理しているので無関心ではいられない。1年で1万ちょっとくらいなら払ってもいいかな~と思っていたら後から月100ドルという話を聞いてひっくり返った。

念のため元ツイートを確認。一瞬月100ドル「以下」のように読んでしまうが、そういえばチルダは英語だと「およそ」とか「約」を表現するのだった。やはり月100ドルらしい。

ゲーセンに行くため外出した。チュウニズムデュエルがまだ結構残っており、具体的には02/08までに35クレ程度プレイする必要がある。1日で終わらせるには厳しいので早めに行動する必要がある。ミスタードーナツで少し腹ごしらえして、午後8時過ぎから閉店までプレイした。

今日の成果はそこそこ。前回ゲーセンに来た時埋め切れなかった14+でSSSを出した後、最近触っていなかった14+をいくつか詰めてSSS+を四つ増やした。その後少し理論値狙い。

なんと13+のきゅうくらりんの理論値を出せた。結構好きな曲なので嬉しい。今日は中盤の微ズレが上手かった。3個並んだノーツのうち右端がズレているなら左手1個右手2個に分け、真ん中がズレているなら左手2個右手1個に分け、手を傾けてスライダーにタッチするタイミングをずらすように意識したら安定した。

ラーメンを食べて帰宅。シャワーを浴び、しばらくTUPCのテスター作業をしてから、午前3時から3時間ほどインターンの進捗を産んでいた。ツールのドキュメントやブログとにらめっこして自動化したいことを実装。幸い今の目的とかなり近い記事を見つけたので思いがけず捗り、ツールの下調べどころかもう実際に使える状態になったのではないかと認識している。

しばらく布団でなろうを読んで午前7時半就寝。

02/03(金)

午前10時ちょっと前に起床し、博論発表会のZoomに接続した。一昨日発表練習に参加した方の発表が朝一番からあった。練習のときスライド中のグラフに関して行った提案が反映されていて嬉しい。

内容自体は特に変わっていないようなので、ゴミ出しの準備をしながら聞いていた。無事終了したのでZoomから退室。布団に戻ってまた寝た。

今度は午後2時ちょっと前に起床し、1on1に参加した。昨日産んだ進捗を報告。自分としてはもう十分自動化できていたつもりだったが、もうちょっと広い範囲をもっと簡単に自動化できるはずらしい。しかし痒いところに手が届かないAPIしか存在しない。いろいろ調べた結果あまり効率的でない方法なら実現可能ということが分かって、それの実装は来週までの自分のタスクとなった。午後4時終了。

午後10時まで先週の集中講義「応用数理総論」の期末レポートを作成していた。5日間あった講義で毎日2題ずつ問題が出され、そのうち片方ずつに解答するのが課題。先週のうちに昨年の資料を参照したり、先生に質問したり、友達と話したりネットで調べたりして最終日以外のものは解けていた。しかしそれらを文章に起こすのは結構時間がかかった。

最終日は順序数に関するもの2題で、まだ考えていなかった。昨年はなかった内容だから今年の資料だけで頑張るしかない。最後だから自力で解こうと思って格闘した。実は後からネットで調べてみたところ必要な定義がメジャーなものと微妙に異なっているらしく、安易に検索に逃げてもあまり意味はなかったようだ。

かなりそれっぽい式変形を行えたがその後のステップがわからない。もう元気がないので適当にまとめてレポートを完成させてしまった。無事提出。これにて今期の講義はすべて終了したことになる。卒業要件に含められない講義二つもなんだかんだ真面目に最後まで取り組めたのでかなり満足している。

Twitterアカウントの凍結が盛んなので、自分も何か対策をと考え、6年近く前に作ったマストドンのアカウントに久しぶりにログインした。有名だったインスタンス5個くらいにkotatsugameというIDでアカウントを持っているが、今は管理が面倒なだけで無駄だったなと思っている。そのインスタンスの一つであったfriends.nicoが結構前に消えていてびっくり。

しばらくフォロバ作業に勤しんでいたが、動作がかなりモッタリしていて嫌になった。Twitterのような快適さを求めるわけにもいかないので、本当に自分のアカウントが凍結されてしまうまでマストドンに移行することはできないのだろうなと考えた。

食事して午後11時半からCF #849 div.4。

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

ABはよい。Cは両端を見て文字が異なる限り縮めていき、残った長さが答え。Dは全通り計算できる。文字の出現をbitで管理したが、一か所__builtin_popcountを忘れて答えがとんでもない値になっていた。気づくのに少し時間がかかった。

Eは隣接という条件を忘れて2個ずつ符号を反転できる。負の数が偶数個あれば全部反転するべきで、奇数個なら負の数を1個残すか、正の数を巻き込んで1個負の数にする。書いてから、これは結局絶対値が最も小さい値を負にしているのだということに気づいた。

Fは1回操作する場合999999999\rightarrow 81、2回操作する場合79\rightarrow 16が操作後の値が最大になるケースなので、高々3回操作すればもう値が変化しなくなる。よって、まだ変化する余地のある値のインデックスをsetで管理しておくと、そこに入っているインデックスに対しては愚直に操作しても間に合う。

G1はスタートとテレポート先が常に座標0なので、そこからテレポーターまで移動して座標0に戻ってくるサイクルに分解して考えることができる。各テレポーターについて1サイクルにかかるコストを計算し、安いほうから貪欲に取ればよい。

G2はテレポート先が2か所に増えている。基本的にはどちらか近いほうからテレポーターまで移動してどちらかに飛ぶというサイクルに分解してコストの安いほうから取れるが、最初の1回だけは座標0から移動する必要がある。貪欲に取ったときにそのような移動が含まれるなら答えはそれで確定する。そうでない場合の処理に苦労した。

最初に座標0からどのテレポーターに移動するかを全探索し、この時余分に増えたコストも含めてc以下に抑えるため貪欲に取った解をどこまで削除するか考える。貪欲解に含まれないテレポーターならどうとでもなる。含まれる場合は二分探索するが、このとき座標0から移動する予定のテレポーターを除いて考える必要がある。実装に手間取ってG1まで解くのにかかったのと同じ時間をG2にかけてしまった。

40分弱で全完、最終順位は12位。動画を撮っていたので編集・エンコード・非公開状態でのアップロードまで済ませ、コンテスト終了を待って公開した。

www.youtube.com

朝まで日記を書きながら社築さんのサーモンラン配信を見ていた。普段見ている「総理大臣によるサーモンラン」シリーズとはかなり立ち回りが違うように思えて目新しく、面白い。総理大臣はコンテナからあまり離れないイメージがあるが、社築さんはステージをかなり広範囲に渡って動き回る。うっかりカンスト達成まで見届けて午前7時就寝。

www.youtube.com

02/04(土)

午後1時半起床。食事して午後2時からUniversal Cupの2回目に参加した。今日のセットは中国のICPC由来でHong Kong Regional。

2022-2023 ICPC Asia East - Hong Kong Regional Contest - Dashboard - Contest - QOJ.ac

チームでKAHBELDFCを解いて9完、41位だった。自分はABDCを解いた。

コンテスト開始早々に通されたのがABHKLで、Kをぷらさんが、Hをかっつさんが通した。Hは難読だった。全員で問題文を読んだが結局細部はよくわからなかったので、サンプルからエスパーしてそれっぽい解法が提出された。

Bは考察すると黒マスに囲まれた白マスの連結成分数を求めればよいことになって、実はこれは右と下のマスが黒で塗られた白マスを数えるのと等しい。なぜならマスの塗り方から、そのように塗られている場合それより右あるいは下に同じ連結成分のマスが存在できないから。何とか思いつけてよかった。

Lはそう簡単に解ける問題に見えない。EFが通されてきたのでそれにも目を向けた。Eは区間\pm 1加算しながら区間の0の個数が分かれば解けることになって、そこで詰まっていたらぷらさんがセグ木に最小値とその個数を持つ方法を出してくれたのでそのまま実装してもらった。言われてみれば見覚えがある。

かっつさんがFと格闘しているのを横目にいよいよLを詰める。それっぽい貪欲がいろいろ思い浮かんで、その中から大きな値から削除することが正当であると示せた。残りの考察や実装はぷらさんにお願いした。1WAしたのでコードを読んだり証明を見直ししたりするも間違いが見当たらない。問題文に立ち返ったところでbaの部分列であることが必要だと気付いた。自明な条件過ぎていつの間にか忘れ去ってしまっていた。

かっつさんのFの考察を見に行った。隣り合う2数の桁数の差は1以下であると書かれていて、すぐにはわからなかったが精密に不等式を評価すると確かにそう。直感的にはどの位置にある2数も桁数の差が1以下になりそうだが示せない。しかし実は隣り合う2数に関する条件だけで調べるべき状態数が十分少なくなっているのではないかと思った。残りの詰めや実装はそのままかっつさんに押し付けた。

CとDが解かれていて、どちらかというとDのほうがとっつきやすそうなので考え始めた。DAGの辺u\rightarrow vについて0\lt v-u\le 1000という制約が明らかに怪しい。ということでまず頂点をサイズ1000のブロックに分けてみたものの、先に進めなかったので別の方針を考えた。

各頂点に対し、そこにたどり着くために使った黒の辺の数と白の辺の数をペアにして持ちたい。このペアは大量に存在しうるが、それらを平面上の格子点だと思うと答えに関わるのは左下凸包に乗る点のみ。そして座標の範囲[0,m]\times[0,m]の中で凸包に乗る点の数はO(m^{2/3})なので、実は持っておくペアはそれなりに少ないことが分かった。あとは実装すればよい。かっつさんのFの実装に割り込む形で書き始めた。

凸包を取るのに失敗して1TLE、また答えを求める二分探索が失敗していたようで2WA。持っているペアを全部試して答えを求めても十分間に合うため、最終的にはそれで通した。TLEは手元で最大ケースを試せば分かったはずだから三つとも不必要なペナ。下手くそだった。

その後Fが無事通った。かっつさんに押し付けてからノータッチだったので何もわからないが、自分では実装したくないような面倒さだったから本当にありがたい。

その間にCの考察を進めていた。nmが奇数なら当然不可能。また行・列のパターン数が足りない場合も不可能。それ以外の場合を考える。mが偶数として、マス目をn\times m/2に分割し片方をもう片方の反転で埋めれば白と黒の数に関する条件を満たせるので良いのではないかと考えた。ただしこれは行のパターンを2^mから2^{m/2}にしているため、mが小さくてnが大きいケースでは使えない。

ちゃんと評価すると、そのようなケースはm\le 18にしかないと分かった。このケースは行のパターン2^m通りを配列で持てるため重複チェックが楽になる。またm\lt nもわかるので、最初にm\times(m+1)マスに白黒同じ数ずつ埋めて列の重複が起きないようにした後、残りの行をx\lnot xをペアにして埋めていくことにした。偶奇が壊れる部分などは適切に頑張る。まずこれを書き上げて、チェッカーも書いて正しいことを確かめた。

残りは結構簡単。最初に2^k\ge m/2を満たす最小のkを取り、上k行を使って列の重複をなくしておく。縦に2進数として見て1\dots 2^kとなるように埋めればよい。残りの行は横に2進数として見る。まず0を置くことで全体を反転しても列の重複が起きないようにする。ここで先ほどの埋め方だと上k行には0がないのも重要。その後0からどんどん値をインクリメントしつつ、上k行とのみ重複チェックして置けるものをどんどん置いていった。

チェッカーを動かして確かめる。すべてのケースは試せないが、小さいケースと大きいケースでOKだったので自信はかなりあった。出したら一発で通った。

残り1時間はGを解こうとしていた。最初は単なる扇形二つの和だと思ったがサンプルが全然合わない。必死に図を描いて考え、サンプルを何とか合わせたと思ったのにWA。結局解けなかった。後から確認したらサンプルすら合っていなかったようだ。小数点以下が違うのを見落としていた。

コンテスト後は先週と同様感想戦をしていた。今日は結構いろいろな問題の考察に顔を出していたので、上に書いた以上のことはほぼない。Kだけ何も知らなかった。いくつか解の候補がある問題らしく、いくつかペナを出しているチームが多い中、素早く列挙してちゃんと一発で通しているのはかなり偉いと思った。

雑談に移行してこの先のコンテスト予定を確認しているとき、次の水曜日にCodeChef Cook-Offがあるのを見つけた。この日はホスフィンと家飲みをする予定が入っている。ちゃんとCLISTも確認していたはずだが、こんな直前になって生えてくるとは。連絡して家飲みをその次の日にずらしてもらった。スケジュールを頑張ってすり合わせて決めた予定だったので、かなり申し訳ない。

午後8時解散。シャワーを浴びて食事した後ABCの録画のセッティングをしていた。せっかくWebカメラがあるので手元を映してみたい。これまでは一枚画面をShadowPlayで撮ることしかしていなかったが、実は配信のためにインストールしたOBSでも録画はできて、これだとカメラ映像も取り込めて画面に自在に配置できる。セッティングとはそのための設定と、Webカメラを手元が映るように置くことだった。

午後9時からABC288。

Toyota Programming Contest 2023 Spring Qual A(AtCoder Beginner Contest 288) - AtCoder

Aは見た瞬間AWK。それ以外はC++で書いた。Bはソートしてから上位K人を答えると思ったら上位K人をソートして答える問題だった。CはUFに辺を追加していって、連結成分が減らなかった本数を出力する。

Dは難しかった。K=2なら交代和が0になることが必要十分条件なのでKが一般の場合も同様に解けると思ったが、それほどうまくいかない。手で実験して、列の長さが2K以上のとき左からK項を0にしようとしたらその次のK項にどんな変化が生じるかを求めた。具体的にはK=4のとき(a,b,c,d,e,f,g,h)\rightarrow(0,0,0,0,e-d+a,f-d+b,g-d+c,h-d+d)となる。正確にはhは操作されないが、巻き込んで考えると規則的。

これをどんどん適用することで、どんな長さの列も長さ2K未満の列に帰着することができる。あとは貪欲に操作すればよい。添え字\bmod Kごとの累積和が必要になって頭を壊してしまったが、何とかサンプルを合わせて提出し、通した。

Eはdp。商品番号iを昇順に見て、これまでいくつの商品を購入すると決めたかjを状態に持ってdpする。商品iを購入するタイミングを適当にずらすことで、定価から値上げされる金額としてC_{j+1}\dots C_iのみ、またその範囲のどれでも選ぶことができる。したがってC区間MINによって価格が決められる。

Fはちょっと難しかった。1文字ずつ見て、その直前の文字との間に区切りを入れるか入れないかでdpを行いたい。和だったら楽、というか何度か見たことのある問題だが積なので複雑。直近で区切りを入れた位置より左に対する値Pと現時点の答えSをペアに持ち、数字vを追加するとき、区切りを入れるなら(P,S)\leftarrow(S,Sv)、入れないなら(P,S)\leftarrow(P,10S+Pv)となって、線形性が成り立つからPSそれぞれありうる状態すべてについての和だけを管理できる。

この状態の持ち方は適当に思いついたもので、試して実際に答えが出たときはびっくりした。線形性なども後から確認したこと。素早く解けてよかった。

Gは解けなかった。3進表記で0と2しか現れないような位置に対しては、それぞれ包除原理することで答えが求まった。しかし1が現れる位置は何一つわからない。正確にはこれも包除原理すればできるはずだが計算量が大きすぎる。

6完88位。ちょっとひどい順位だがとりあえずオンサイトには出られるようだ。Dは差分を取る典型が効くらしいがK=2のときの交代和に引きずられてしまった。

Gを3桁人が解いていてひっくり返った。競プロフレンズさんがB\rightarrow Aを考えると解けたと仰っていて確かにという気持ちになった。しかしその時点で解説を読んでいたので、本当にそのアイディアだけでコンテスト中に解けたかはわからない。

コードゴルフ。AはAWKでよい。BはVimだった。書こうとすらしていない。CはPerlで、UFを使って森の辺の数を数える問題はいくつもあるのでそこからコードを引っ張ってきたが、この問題用に書き直す部分で負け。FはPerlがかなり短くなった。他は手付かず。

ABCの録画を編集して投稿した。せっかく手元を撮ったのだから出したいという欲求が、Gを解けなくて恥ずかしいという気持ちを上回った。

www.youtube.com

しばらくPCの前でなろうを読んでいて、寒くなってきたので布団に潜り込んだらすぐ寝落ちしてしまった。午前4時くらいだった。

02/05(日)

午前9時半から午後3時まで起きていて、ずっとなろうを読んでいた。「異世界転移で女神様から祝福を! ~いえ、手持ちの異能があるので結構です~」を読了。

https://ncode.syosetu.com/n2031cu/

面白かった。多人数で異世界転移したのに主人公(ともう一人)がすぐ排除されてしまう、というところまではテンプレだと思う。あまり読むジャンルではないのでその先の展開がどれだけ特徴的かはわからないが、排除された主人公たちが実はめちゃくちゃチート持ちで爽快だった。

最初は単に異能をいろいろ持っていて強いという感じだったが、後から元の世界でも非常に特異的な人間だったと明らかになる。最初からそういう設定があるとさすがに盛りすぎと思ってしまったところ、途中から徐々に明かされていくので無理なく受け入れることができた。主人公の豪運っぷりが見ていて楽しい。

また寝て、次に午後7時起床。1時間ほどなろうを読んで布団から脱出した。

食事してCFに向けた準備をした。今日も手元を含めて録画するつもり。昨日はメモ用紙が体の影になって見えにくかったので、前からデスクライトで照らしておくことにした。顔をモニターに向けるとちょっと眩しいが耐えられないことはない。あとはカメラの位置も調整して、メモ用紙がより大きく映るようにした。OBSでカメラ映像の画面全体に対する比率も大きくした。

午後9時からCF #850 div.1。久しぶりのcombinedでないRatedだ。

Dashboard - Codeforces Round #850 (Div. 1, based on VK Cup 2022 - Final Round) - Codeforces

Aはなぜか一つ目の呪文も全モンスターに1ダメージ与えると思い込んでしまい少し手間取った。適当に1から連続する値を作ると二つ目の呪文で全モンスターを倒せるので、そういう連番を作るために与えるダメージを最小化する。ソートして貪欲でよい。サンプル2に怪しげな数字が並んでいて面白かった。

Bはwinに対応する頂点を作り、各sを見ていらない文字から必要な文字に向かう有向辺を張って考えた。文字のswap1回によってある辺とその逆辺を消せる。また2回swapすれば長さ3のサイクルを消せる。直感的には前者を貪欲に行った後後者で調整すればよい。

実際、前者を行えるだけ行った後の辺は、長さ3のサイクルにちゃんと分解できる。有向辺としてsに必要な文字が存在するという意味の自己ループも考えると、三つの頂点はどれも入次数、出次数共にmとなるから、逆辺を持たない辺しかなければそれぞれ対応する長さ3のサイクルが存在する。

復元が面倒そうだったが、頂点の組に対しその間にある辺に対応する人の番号を持つと結構簡単に書けた。一発AC。

CはAの強化版。値を追加しながらAを解く必要がある。真面目に追加していくとしても遅延セグ木があれば解けないこともなさそうだが、細かいところで実現不可能な操作が要求されるように見える。考え方を変えて値を削除しながら解こうとしたらかなり簡単に解けた。

まずAの解法を整理する。aを適当に並べ、先頭からできるだけ遠くまでi\le a_iが成り立つようにする。m\le a_mまで成り立つとすれば、このaたちに対する答えは\sum_{i=1}^m(a_i-i)となる。1\dots mというのが上で述べていた連番である。

a_1\dots a_mに使った値から1個削除すると、代わりに削除した値以上の使っていない値を埋めて連番の長さを保つか、諦めて連番を一つ縮めることになる。前者は使っていない値をmultisetに入れておくと取得できる。後者については単に削除した要素より後ろを一つずつ前にずらせば条件を満たせる。m\sum_{i=1}^m a_iを管理しておけば答えが求まる。

Dは面白かった。人uに注目しているとき、残りの2^n-1人を2^0,2^1,\dots,2^{n-1}人に分けることができる。これはuからトーナメントを表す完全二分木で上に登っていくとき、uを含まないほうの部分木に含まれる葉の数、つまり人数を意味している。作ったn個のグループそれぞれで番号の最小値を求めると、それがuを先頭にした順番で単調減少であることと、uがそのトーナメントでWooden Spoonとなることが同値。

グループ内の並び替えや二分木の子の左右は単なる係数だから後から掛けることができる。よって番号の最小値に関する条件を満たすような分割を求めればよい。挿入dpを考えた。大きなグループから順番に挿入していく。挿入したグループの中で番号が最小の人が先頭から数えてどの位置にいるかを状態として持てば条件のチェックができる。一つのグループに対して状態数は高々2^nであり、遷移も累積和を取ればまとめてO(2^n)となる。これをグループの数だけ繰り返せば、最後に挿入した一人がuに対応する。その番号はdpの状態としてわかっている。

Eに2時間近くかけたが解けなかった。現在行われているsetにおけるAliceとBobの勝ち数はちょうど4状態しかなく、それぞれからスタートしてsを一周し、戻ってきたときの勝ち数の状態とAlice・Bobの勝ち数の差が求まれば、ゲームの進行をシミュレートできる。いずれループに突入してそこを無限回周回するから、答えはそのループ一周におけるAliceとBobの勝ち数の大小と一致する。

つまりsを一文字ずつ見ながらスタート4状態に対する現在の状態とAlice・Bobの勝ち数の差を求めていけば解けはする。この時点での状態数は高々(4|s|)^4、実際は実現不可能なものがそこそこあって大幅に減っているがACには遠いようだ。ここからどうやっても削減できなかったので、遷移をビット演算を駆使して高速化してみたところ、最大ケースで7.5sec程度にはなった。当然通ることはなくそのままコンテスト終了。

4完47位で2905→2914(+9)。撮った動画をE問題に苦しんでいる2時間も含めほぼそのまま投稿した。AviUtlで前後を少し切り落としたらエンコードに1時間半かかって大変だった。どうせ大した編集はしないのだから、一度投稿してからYouTubeの機能でカットすればよいのかもしれない。

www.youtube.com

Amazonでいろいろ注文した。まず来週木曜日の家飲み用の缶詰とボドゲ。お酒はホスフィンによって提供される予定だ。次に、本棚と転倒防止の突っ張り棒を買った。部屋の机の上にはラノベが山と積まれており、何かあったら崩れそう。どうせホスフィンを家に上げるときどこかに動かさなければならないのだし、今買うのがちょうどよい機会だった。

昼間まで日記を書いたりなろうを読んだりしていた。午後0時半就寝。