/ 最近 .rdf 追記 設定 本棚

脳log[2022-07-04~]



2022年07月04日 (月) [AtCoder] 精進。第10回PAST-L「N mod M」。第10回は手持ちの道具では解けなさそうな N 問題「400億マス計算」以外では L 問題だけが解けずに残っていた。余りをとる M が合成数でなければ 9 の逆元が使えて解けるんだけど。■提出 #32992192 (AC)。AC につながるヒントを見ました。「Lは10^D-1を mod 9M で計算することで、直接9で割れるようにするテク」。言われたらそれだけのことで、半完成だったスクリプトをゴミ箱から拾ってきてちょちょいといじるだけで完成したのだけど、独力ではたどりつけないのだよな。これくらいのことは mod について 1 を聞いて 10 を知るどころか 2 を知る程度の理解力で把握できそうなものだけど、脳みその使い方を知らない。■Ruby によるすべての提出を見ると解法は1つでも2つでもなさそうな雰囲気。どれ1つわからなかったな。


2022年06月29日 (水) [AtCoder] 精進。第10回PAST-O「3-順列」。やりたいことは比較的わかりやすいと思う。グラフがあって、二部グラフとそうでないものがある。N 個の3の剰余があって、0と1、2 がある。0はどんなグラフにも当てはめられるけど、特に二部グラフでないものには剰余が0になる数しか割り当てられない。なのでまず余りが1と2になる数を最大限二部グラフに割り当てる。孤立した頂点にも1と2を割り振る。1と2を使い切って残りが0だけになったら、残ったグラフに割り当てて答えは Yes。二部グラフでないものに1か2を割り振るようでは答えは No。■提出 #32841134 (AC / 1176 Byte / 301 ms)。実装が難しかった。二部グラフに1と2を割り当てる方法。使った1と2の数で二次元二値の DP をして、使った個数の和を最大化すればいい。それがわかってもいざ実装すれば3つも4つもバグり散らかしていてデバッグに大変苦労した。


2022年06月28日 (火) [AtCoder] 精進。ABC151-F「Enclose All」(ギリギリ青 diff)。初めて見る問題。円をそれ以上小さくできなくなる状態がどういうものか想像すると、複数の点が円周上にあってそれ以上半径を縮めたり中心座標をずらしたりすると点が突き出てしまう均衡状態かな、と。そういう円は3点で決まるような気がしたけど4点になることがあるような気もした。テキトーな実装をする前に外接円について検索して「外接円 - Wikipedia」を読んで「最小包含円 - Wikipedia(en)」というものを知った。そこでアルゴリズムがいくつか紹介されていて、線形時間のアルゴリズムは難しかったので2番目に書かれていた Welzl's algorithm を実装した。■提出 #32821823 (AC / 992 Byte / 59 ms)。Wikipedia の言いなりに実装しただけなのでなんとも。最初の想定の答え合わせをすると、外接円は3点もしくは2点で決まるものを考えればいいのであって、4点を考える必要はなかったらしい。なんでかはわからない。垂直二等分線を引いて2点を満足させる円、3点を満足させる円を考えてみて、それから4点を満足させようとして偶然頼みになることを確認したりしてみればいいんじゃないでしょうか。■他の提出を見てみると最速級のものに「最小包含円 | libalgo」に書かれているのと同じ3重ループが目立つ。アルゴリズム的には自分が参考にした Welzl's algorithm と同じなんだろうか。自分が参考にして書いたのは再帰関数だったけど、再帰呼び出しの最奧の停止条件を初期値にして、再帰呼び出しからのリターンが多重ループへの飛び込みに対応するような、内外を裏返しにした相似構造が見える。


2022年06月27日 (月) [AtCoder] 精進。前回の ABC-E に関連して「既視感がある問題。それも WA がいつまでも取れなかったことで記憶に残っている」と書いていた問題。ABC118-D「Match Matching」(ギリギリ青 diff)。16 個の WA/RE 提出の末に 4 WA(#13237877) まではいっていたのだけど行き詰まっていた。それから2年を経て改めて問題を読めば、DP だろうなあと嗅覚が働く。3年前も2年前も謎の貪欲法(バックトラック付き。つまり打ち切りありの再帰)でやっていたみたいだけど。■提出 #32816278 (AC / 361 Byte / 71 ms)。マッチの本数に対して桁数の最大値を記録する DP をやって、なんとなーく経路の復元をして答えとした。DP の復元という比較的最近仕入れた概念は『典型90問』の成果。限られたパラメータを広範囲に展開して書き込むよりもっと上手い方法があるんじゃないかと思いつつ、ループの中で DP 配列を右へ左へ全長に渡ってなめなめ更新しても許されているのでまあいいか。■他の提出を見ると Ruby なら桁数でなく作った数そのものの最大値を記録するのでも良かったらしい。だけどこの問題を連想させた問題で Bignum に起因して TLE になっているので、そういう選択はできなかったな。最大で 5000 桁になるのを確認して避けたもんな。■Ruby で最速の提出はいずれも答えの数字を3つの部分に分けて考えているようだった。2年前の自分が 4 WA を解消できなかったのはこの構造が見抜けていなかったせいだろう。貪欲さが足りなかった。


2022年06月25日 (土) [AtCoder] 今日は 日鉄ソリューションズプログラミングコンテスト2022(AtCoder Beginner Contest 257) があった。自分のすべての提出。13 分余分にあれば6完だった!(空しい反実仮想)■特に書くことはないかな。(F 問題までの)傾向としては易化、典型寄りだったと思う。F 問題でも PAST の真ん中あたり(J とか K)に出そうな雰囲気。そういうときに点が取れないでどうするの?■C 問題で質問したよ。S の i 文字目を右から数えるのか左から数えるのか、問題文はわかるように書かれていないし(S=S1S2S3...Sn から成る。Si=1 のとき……とか。「Shortest Good Path」がそんな感じ)、サンプルの S がどれも左右対称だったから手掛かりがなかった。ビットなら LSB から数えるだろ常考、で納得するけども、文字列の常識は知らない。■解けたから簡単だというのは嘘だな。考えたことと罠を書いていこう。■C 問題「Robot Takahashi」。X が実数って書いてあるけど、与えられた数値(W)と、与えられた数値よりも(ちょっとだけ)大きな値だけを試せばいいよね。尺取りをすれば N の制約上限 20 万もクリアできる。与えられた数値よりちょっとだけ大きい値を試す必要があるのは、X 未満の子どもという条件で max(W) を勘定に入れるためには max(W)<X である必要があるから。■D 問題「Jumping Takahashi 2」。問題文を誤読したまま考えていた。つまり、あるジャンプ台からスタートしてジャンプを繰り返しながら全部のジャンプ台を巡らなければいけないのだと思っていた。サンプルを読めば間違いがわかるのだけど、頭の中でひと通り試行錯誤して実装してからサンプルを試す段階で初めて気がついた。ワーシャルフロイド法で解ける。■E 問題「Addition and Multiplication 2」。既視感がある問題。それも WA がいつまでも取れなかったことで記憶に残っている。調べたら初めて参加した ABC の D 問題「Match Matching」のことだった。しかもまだ AC してなかった>自分のすべての提出。ちょうどを要求されていない点で今日の E 問題の方が簡単だったのでは? その E 問題。問題文を読めばどの i を選ぶかよりも操作回数を最大化することが大事だとわかる。まずは最小コストの数字を使用して桁数を最大化する。次に桁数を減らさない範囲で最大限 i を 9 に置き換える。それから 8,7,... と順番に残された条件の範囲で桁数を減らさない限りにおいて i を i より大きい数字に置き換えていく。罠は答えの出力方法。サンプルに「答えが 64 bit整数型に収まらないこともあることに注意してください」と書いてあるのだけど、これをよくある 32 bit整数型に収まらない場合の警告だと思って、でも上限がどこかに定めてあるんでしょうと問題文をさらったけど見つからなくて、Ruby だからと深く取り合わずに提出したら TLE になった。答えを文字列で持つのが正解。■F 問題「Teleporter Setting」。これも最初は問題文が読めていなかった。求めるのは 1 から N までの最短距離。それに不定なテレポーターがどう寄与するか。不定なテレポーターが寄与しないなら普通に町 1 から BFS した距離表(D1)でもって D1[N] が答えだし、寄与するときに考えるパターンは2通りしかない。つまり、1 から i を目指すより 1 から 0 を目指した方が近いパターンと、N から i を目指すより N から 0 を目指した方が近いパターン。それだけではない気がしたとしても、それだけ。■コンテスト時間中に 4 WA と自分より先を行っていた提出 #32743897 をデバッグしようとして 30 分以上考えている。予想だけど、町 1 と町 N が不定なテレポーター(0)を介して連結な場合が抜けていると思う。たとえば 1-2-0-9-N というグラフ構造のとき、i の値によらず min_a+min_b+2 が答えの候補としてある。


2022年06月24日 (金) [AtCoder] 精進。AGC056-A「Three Cells per Row and Column」(水 diff)。N が 3 の倍数のときは簡単だけど 3 で割り切れないと難しい。1 余る場合と 2 余る場合を手で構築してうまく敷き詰められないかと思ったけどうまくできなかった。■提出 #32694973 (AC / 582 Byte / 68 ms)。Array#sample と Array#shuffle! の使用がすべてを物語っている。テキトーにコンピュータに構築させたらええねん。■「テキトー」の解説。1 から N の順列を 1 つテキトーに選んで、i 番目の値が j のとき、j 列の i-1 から i+1 行目を # にする。順列の中で隣接 3 要素の少なくとも 2 つの値が連続しているときは上下に伸ばした # が連結してしまって不都合なので、そういう順列は不採用にする。1 行目から上に伸ばした # と N 行目から下に伸ばした # の扱いが特殊だけど、それぞれ N 行目、1 行目の同列に配置すれば行の条件と列の条件は満たす。そのうえでそれが N-1 行目、2 行目から上下に伸ばした 3 マスと連結になるなら連結成分の条件も満たす(このとき 2 マスの連結成分が 2 つと 4 マスの連結成分が 2 つできている。他は 3 マス)。■自動生成するまで気がつかなかったけど、N が大きいほど構築はテキトーにやって失敗しない。むしろ条件設定を失敗して N=6 の場合に構築できない(どの順列も条件を満たさない)ケースが目立った。人間は N=6 が一番簡単なのになー。


2022年06月23日 (木) 5年ぶり2度目にスタートした Salt and Sanctuary を今回はクリアした。先月発売された Salt and Sacrifice の前作。全然覚えてなかったけど5年前も今回も全く同じ大槌を振り回していて、同じ頭をくっつけた人間って同じ道を辿るのだなって。つるっぱげの女の子キャラでプレイしたけど、とってもかわいいし着せ替えも楽しい。手と足は重装で胴は軽装もしくは下着。頭は好みで。


2022年06月22日 (水) [AtCoder] 精進。ABC169-E「Count Median」(水 diff)。コンテスト当日に 23 分で D まで解いていながら残り 77 分で解けなかった問題。当日と後日を合わせて 6 WA している。■提出 #32668994 (AC / 210 Byte / 316 ms)。秒で考察が終了して実装量もご覧の通り。むしろどこでどう迷っていたのかがわからない。コンテストで安定した成績を残したいなあ。■考えたこと。中央値を最大化したいとき、数列の半分を上限(B 数列)に張り付かせればいい。反対に中央値を最小化したいとき、数列の半分を下限(A 数列)に張り付かせればいい。N が奇数のときは単純に N/2+1 番目の上限と下限のあいだが中央値として可能な範囲。N が偶数の時は、N/2 番目の上限下限と N/2+1 番目の上限下限を同じように求めて、その和(下限+下限と上限+上限)が取り得る範囲を定める。■どこで迷っていたのか思い出した。各要素が取り得る範囲が Ai 以上 Bi 以下という形で制約されているので作れる中央値の範囲(上限と下限のあいだ)に抜けがあるのではないかと考えたのだった。その不安はわかる。わかるけど、問題設定の理解が足りないせいで書かれていない制約を自分で作り出していませんか、と今となっては思う。望みの中央値を作るに際してどういう操作が可能か限界がどこにあるかよくよく具体的に考えてみれば。


2022年06月21日 (火) [AtCoder] 精進。ABC187-E「Through Path」(水 diff)。コンテスト当日に 25 分で D まで解いていながら残り 75 分で解けなかった問題。翌日のふりかえり>20210103p01。「全然ループの軸が見えなかった」と書いてあるが、以前も今日(の最初)も問題の形式に引っぱられて辺を中心としたループしか考えられていなかった。考えるのは頂点について。■仮に定めた木の根によって決まる親子関係とクエリの種類(t)によって、クエリは、a か b を根とする部分木に x を加算するか、部分木以外に x を加算すると理解される。部分木に加算するのはオイラーツアーと累積和の組み合わせでいけるし、部分木以外に加算するには全体に x を加算してから部分木を対象に -x を足せばいい。■提出 #32649747 (AC / 577 Byte / 832 ms)。以前の日記に「筆塗りを思い出した」とも書いてあるから当時からオイラーツアーは知っていた。硬直した視点が解けなかった唯一の理由。■解説を読めばオイラーツアーはいらなかった。それはクエリを処理しながら質問にも答えたいときに BIT を使って累積和の構築を高速化する方法。解説の最後に「また、各クエリで辺 e 以外では cai​​−cbi​​ の値が変わらないことに注目し、c1​ と cai​​−cbi​​ の値を管理しても同様に解くことができます」とも書いてあるけど、えっと、よくわかりません。■■■木の全体を変化量(差分)の連鎖として見る。頂点の値は変化量の累積。変化量の累積は相対値なので木全体の値を一意に定めるアンカー(初項)として c1 に代表させる。根っこの値を代表値にすると都合がいいのは、親子関係で辺の向きが判別できるから。■提出 #32651136 (AC / 408 Byte / 958 ms)。時間もメモリ使用量もさっきの提出に劣ってるのが納得いかない。いやまあ、判断と計算を先送りしたせいでややこしくて、判断と計算の材料を蓄えるために余計なメモリを使ったんだろうなあとはわかる。報いがない。でも先送りせんと辺に注目してるのか頂点に注目してるのかわからんようになるのでしかたなかった。解説の最後の1行ってこういうことだと思ったんだけど違うかな。


2022年06月20日 (月) [AtCoder] 精進。昨日あった ARC142-C「Tree Queries」(水 diff)。昨日は 1 を含む辺からの距離一覧を取得したらどうだろうかとか、1 と 2 をどちらも含まない辺からの距離一覧を取得してみたらどうだろうかとか考えていた。どちらの場合でもうまくいかない木の形がある。そのうちに提出できないまま時間が終了していた。今日になってお風呂に入るや思いついたのは、(仮に 3 を根として) 1 と 2 のうち深い方の親を押さえてしまえばどうだろうかということ。親を特定することはできる。それで 1 と 2 の距離を求めることができる。クエリ回数は 2N-3 回で足りる。このツイートのケースも大丈夫。■提出 #32630348 (AC / 447 Byte / 66 ms)。これを思いつきでなく見つけられる脳みその構造が理解できない。■Ruby によるすべての提出をちらちら見てるけど、1 からの距離一覧と 2 からの距離一覧を取得する提出が複数(というかほとんど?全部?)目についた。えっどういう解き方?■解説を読んだら書いてあった。コンテストが終了してから今日までのあいだに 1 からの距離と 2 からの距離を見比べる方法を自分でも考えてはいた。1 と 2 のパス上にある頂点なら和が答えだし、パスから外れている頂点なら対称差(XOR)にあたる部分が求められたら……とか。解説にいわく「Di​ の最小値は多くの場合 d1,2​ に一致します。」 和の「最小値」が「多くの場合」答えに一致するとか、そんなざっくりした掴まえ方は出て来んで。結果として自分と同じ考え方の提出が全然見つからないのはとても嬉しい(そういうタイプの人間)。


2022年06月17日 (金) [AtCoder] 精進。第6回PAST-L「都市計画」と第1回PAST-L「グラデーション」。都市計画を解いたら以前解けなかったグラデーションと同じ問題だったのでそちらもついでに解けた。都市計画自体も以前解けなかった問題だけど、それは 20211031 に Cosmic Rays を解いていたから。初見で解けなかった Cosmic Rays が解けたのは日を空けて問題文を2回読んだから。解けるまで挑戦すれば必ず解ける!(ただし期限が有限とは限らないが生は有限)■すべての頂点が同じ扱いなら迷わず UnionFind でクラスカル法なんだけど、必須ではないオプションの頂点があるせいで困ってしまう問題。全探索するならオプションを仮にいくつか必須扱いにしてそれが最適ではなかったとしても他の試行でカバーできるから問題ないんだよね。先日「難しいなこれ。ある時点のループにおいてベストを求めなくていいし不正確でもいいということを見極めて受け入れるのは」と書いたけど、自分はこの手の見極めが苦手みたいだ。■提出 #32497250 (都市計画 / AC / 721 Byte / 176 ms)。提出 #32497605 (グラデーション / AC / 527 Byte / 67 ms)。■■■精進2。第5回PAST-L「T消し」。曲者の T が ABA 型だろうということは以前からわかっていたが、ではそのときの最適な消し方をどう組み立てればいいかがさっぱりわからない。■提出 #32506171 (AC / 341 Byte / 63 ms)。解法ガチャを何度も引きました。AC は偶然との説あり(乱択というわけではない)。■当たりを引いたガチャ解法について。T=ABA のときに S から (A+B)+A+ というパターンにマッチする部分文字列(複数)を抽出してこれを対象にして考えた。それ以外を考えなくていい理由は、A に左右を挟まれていなければ反応が起こらないことと、B が連続していたり A と B 以外の異物が存在している部分を超えては反応が広がらないこと。次にこの (A+B)+A+ 型の文字列で反応が停止する条件が何か。1.A を使い尽くした。2.B を使い尽くした。3.B と B のあいだの A を使い尽くした。1と2は反応物の一方を限界まで使い尽くしているので問題ないが、3のケースでは A と B が A+BB+A+ という形で残っている可能性があり、ここには最適化の余地がなくはない。ここから、A と B を使い尽くすための B を消費する戦略を貪欲法で実装した。貪欲にやって局所最適に陥る危険があるかないかはわからない。


2022年06月16日 (木) [AtCoder] 精進。先日「解きたいなー」と書いていた第6回PAST-G「一日一歩」。最初から「1 日に複数本の道を使うことはできないことに注意してください」の一文を念頭に置いて考えれば、むしろどうしてこれが問題になるのかわからなくなった。パスとか何日目に訪れたとか関係なく、街の集合を一日一日拡大していくことを考えるだけ。とはいえ制約が厳しい。新しく訪問した街があればそこから移動できる未訪問の街を最初に訪問可能になるのが何日後かをセグメント木で管理した。■提出 #32487113 (AC / 995 Byte / 1952 ms)。2183 ms で TLE になったので 200 ms をミクロなチューニングで稼いでの AC。「Ruby によるすべての提出」を見ると他3つの AC はプライオリティキューを使用していて時間も 1216 ms から 1804 ms と余裕があるようだった。たぶん W[X] (X 日目に訪問可能になる街の集合を記憶する配列)に相当する役割を担っているんだろう。■提出 #32487597 (AC / 1027 Byte / 1210 ms)。自分でもプライオリティキューで書いてみた。ずいぶんシンプルに書けた気がしたけど、セグメント木とプライオリティキューのコード量の差により実際にはサイズが増えている。こちらの方が簡単に書けて簡単に読めるけどね。それにも関わらずプライオリティキューを使うんだというヒントをもらうまでは思いつきやしなかったけどね。■■■精進2。第6回PAST-K「共通クーポン」。DP ができなくて解けていなかった問題。■提出 #32492522 (AC / 480 Byte / 340 ms)。N の上限が 10 万だけど、N=10000 で TLE になる明らかにまずい DP をしている。ケースが弱い。■提出 #32492799 (AC / 431 Byte / 215 ms)。こちらが正しい DP。これなら前処理を省いても十分に時間が足りたと思う。この問題の入力は DP よりも前処理の方が効果的であるようなものだけど。


2022年06月15日 (水) [AtCoder] 精進。ABC204-E「Rush Hour 2」(青 diff)。コンテスト後に小数がどうのとか底が2乗付近にあるとかのヒントを読んでいた。■提出 #32477294 (AC / 1049 Byte / 560 ms)。といって、範囲を絞っても線形探索では special_*.txt ケースが1分近くかかって大いに苦しんだのだけど。範囲総当たりに代わる 56 行目の bsearch メソッドが非常に危なっかしく見える。■提出 #32477346 (AC / 1021 Byte / 569 ms)。底が2乗付近にあることの意味を理解していなかった。D/t と D/(t+1) の差が1以下になるまでは到着時刻が早まる可能性があるから調べなければいけないのだと思っていたけど、~までは可能性がある、ではなくて、~付近まで(階段状に)短縮するもしくは横ばいだからその近辺(悪化する直前)だけ調べればいい、だったみたい。実際1つめの提出で bsearch メソッドが調べてるのもそういう位置なんだから当たり前の話なんだけど。意外にも3地点だけを調べるこの提出と二分探索で範囲を調べる1つめの提出の(最悪)時間は変わらない。けれど内訳を見るとやはり special_*.txt には大きな差がついている。毎回の探索範囲が広いという点がスペシャルな所以なのだろう。だから線形、二分、定数の順にタイムが顕著に異なる。