/ 最近 .rdf 追記 設定 本棚

脳log[2022-06-21~]



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 には大きな差がついている。毎回の探索範囲が広いという点がスペシャルな所以なのだろう。だから線形、二分、定数の順にタイムが顕著に異なる。


2022年06月14日 (火) [AtCoder] 精進。第1回PAST-J「地ならし」。たぶん緑 diff から水 diff くらいの位置づけだと思うし、PAST は A から始まって K、L 問題あたりまでは順当に解きたいと思っているのだけど、この J 問題は解けずに残っているうちの1問。■最初に考えたのは、中継地点までの最短経路を求めてから、その経路上の任意の1点を始点にしてゴールまでの最短距離を求める方法。だけどたとえば3点のちょうど中間にあるような地点を経由するルートが、2点間距離を考える上では最短ではないけど、総合的には得をするケースがあるような気がする。一度通った道を再度通るときにはコストがかからないからそうなる。スタートとゴールの最短経路を求めてから中間地点に寄り道するように順番を入れ替えても状況は同じ。では盤面の任意の点を始点にして3点までの最短距離を求める場合はどうか。ここまでは過去にも考えている。そのときわからなかったのは、3点までのルートが同じマス目を共有するケースのコストをどう計算するか。■提出 #32470566 (AC / 574 Byte / 95 ms)。AC に至れた今日の気づきは、3点への最短経路のうち2本が共有地点を持つ場合は、その共有地点を始点にした方が(2点への距離に関して)得をするということ。常にどれか2つの最短経路が共有地点を持つ3すくみの状態に陥いって正しいコストが計算できなくなったりしない理由は、やっぱりよくわかっていない。■たぶん詰めて考えれば、3すくみの2つの状況を取り上げて2つの分岐点が異なる点だと仮定すると最短経路だと思っていたものが実は最短経路でないことがわかってじゃあどこに間違いがあったのかを考えれば2つの分岐点が異なる点だと仮定したところにあったりしてなんだ心配していた状況は起こりえない状況だったんだね良かった良かったとなる気がするんだけど、詰めて考えることができないし、直観でありえないと否定もできない。■次は第6回の G「一日一歩」が解きたいなー。第9回までの F 問題まではすでにコンプリートしていて、G、H、I、J のそれぞれに1問だけ解き残しがある。G 問題は解き残しのなかで最弱……のはずなんだけど、過去に何度も解けたと思ったあとで「1 日に複数本の道を使うことはできないことに注意してください」に阻まれている。それを言われてしまうと厳しい制約の三重苦のもとでどういう状態管理が許されるのかわからなくなるんよ。


2022年06月13日 (月) [AtCoder] 精進。ABC136-E「Max GCD」(ギリギリ青 diff)。操作によって A の総和に変化がないので、A の総和の約数が答えの候補。飛び飛びに存在する GCD の倍数に A 数列の各要素を寄せていくイメージ。操作回数に制限がないなら総和そのものが答え。1は常に可能な答え。それ以外の答えを約数の大きい順にテストしていく。■提出 #32461534 (AC / 448 Byte / 131 ms)。判定関数が全然わからなかった。足す数と引く数の釣り合いが必ず取れることは決まっているのだけど、釣り合いが取れるまでの操作回数がわからなかった。Array#insert を繰り返す効率の悪い方法で数えている。


2022年06月12日 (日) [AtCoder] 精進。昨日あった ABC255-E「Lucky Numbers」(水 diff)。S を引き算すると A 数列の奇数項の階差数列と偶数項の階差数列が得られる。つまり、最大 10 個のラッキーナンバーに A 数列を当てはめるにあたり、操作できるパラメータは2つ……ではなくて、S1 = A1+A2 であるから奇数項と偶数項のあいだにも拘束条件があって、実質的にパラメータは1つ。1 WA したあとでそのことに気がついたけど、時間内に完成させられなかった。じっくり時間をかけても WA だったから、取りこぼした5完を悔しがることもできない。今日の提出 #32437476 で AC (3380 ms)。d2 の正しい定義がさっぱり見つけられなかったのが敗因。■Ruby でのすべての提出を見ると一番速いのが 363 ms。3秒オーバーは甘えだということがわかる。AC するのがやっとでさっぱりわからない。


2022年06月10日 (金) [AtCoder] 精進。CODE FESTIVAL 2015 予選A-D「壊れた電車」(青 diff)。■N の制約上限が1ギガだと気付かずに長さ N の配列を埋める解法をまず考えた。左端の人から順番にカバーする範囲(左隣の人から右隣の人まで)の配列に所要時間を埋めていく。隣り合った3人の整備士について考える。真ん中の人が最も右まで(右隣の人の直前まで)カバーするとき、左側をカバーするのに最も時間がかかる。左隣の人に右側をカバーしてもらうのにかかる時間と真ん中の人が左側をカバーするのにかかる時間がバランスするのはどこだろうか。真ん中の人が右側でカバーする範囲を1つ減らすと、左の人と真ん中の人がバランスする時間はどう改善するだろうか。右の範囲をさらに1つ減らすと……。■提出 #32342207 (80/100 点 / 355 Byte)。最も右の人が配列の N 番目を埋める時間が答え。■制約を考慮すれば N についてではなく M について処理を進めなければいけない。使える時間が与えられたとき、M 人の人は N 台の車両を左から順番にそれぞれどこまで修理することができるだろうか。■提出 #32342450 (100/100 点 / 149 Byte)。満点解法の方が短くて書くのが簡単なんだよなあ。自分はややこしい 80 点解法を完成させたことを評価したい。みんながみんな判で押したように解説通りの満点解法じゃ面白くないでしょ。迷えるのは見えていない者の特権!(迷いたいわけではない)


2022年06月09日 (木) [AtCoder] 精進。ABC116-D「Various Sushi」(ギリギリ青 diff)。K 個の総和を大きくしたいけど種類ボーナスがあるせいで若干の番狂わせがあるのをどうするか。とりあえず種類を気にせず大きいものから K 個取る。K 個で K 種類あるならそれまで。種類数が少ないなら、N-K 個の余りからおいしさが大きい順に、種類数が増える限りにおいて、入れ替えてスコアを再計算してみる。入れるもの出すものの選択は貪欲法でいい。■提出 #32335682 (AC / 338 Byte / 238 ms)。二分探索かなとか種類数を固定して考えるのかなとか、種類数を決めても種類の取捨選択で試行錯誤ができないのをどうするかなとか、わりと考えた。考えた結果が「(種類数を増やすにあたり)入れるもの出すものの選択は貪欲法でいい」。■ブログを読んでいると、種類数「の最低ライン」を決めてそれを満たすように X 種類 X 個を選んだあとで、残り K-X 個を無差別に選ぶのでも良かったらしい。種類数を固定するのではなく、種類数の最低ラインを固定する。ただ、こちらは効率的な実装が難しい気がするな。ソート列を2本持って、1本目から X 個取ったあとで、両方から K-X 個を取るような……。あ、Ruby で最速 207 ms の提出 #5420937 における strongyowai_sushi ってそういうことか(2本のソート列)。そして、その提出によれば2本のソート列から K-X 個を取るパートはない。1本目のソート列から X 個を超えて取る方が良くなるケースは、X を増加させた後のループで試行されるのを待てばいいのだから、それはそう。そしてだからこそ、40 行目 tmp = intstrong[t] + intyowai[k - t] + t*t において K 個の実際の種類数が t 種類より多くてスコア計算が不正確であっても(不当に低くても)無視して良い。難しいなこれ。ある時点のループにおいてベストを求めなくていいし不正確でもいいということを見極めて受け入れるのは。


2022年06月01日 (水) [AtCoder] 精進。ABC131-E「Friendships」(水 diff)。苦しんでいた時間の半分以上で木を構築しようとしていた。そうではなく、自己辺と多重辺がないグラフでいい。つい先日(20220526)「Tr/ee」を解くのにキャタピラ木を構築していたのに引きずられている。最短距離が2の頂点ペアが最も少なくなるのが直線状の木で、最も多くなるのが星型の木なんだけど、木は条件じゃあなかった。(木に限らない)グラフが構築できる上限は星型の木と同じだったけど、下限はゼロであり存在しなかった。■提出 #32150851 (AC / 522 Byte)。根本的な軌道修正はできなかった。当初の方針通り三角数と K の値を見比べて星型と直線状のバランスを取りながら頂点を1つずつくっつけていった。「Tr/ee」を解いたのと同じ方針。judge.rb27 を書いたのも同じ。■「Ruby でのすべての提出」を見ると一番短いのがこちら>提出 #6356157 (193 Byte)。すごく単純な二重ループ。■この問題は完全グラフをスタート地点にするのがわかりやすい。全頂点間の距離が1の状態をスタートにする。ここで A-B 間を直接つなぐ辺を取り除くと A-B 間の最短距離がどうなるか。ほぼ完全グラフなのであらゆる経路あらゆる距離が考えられるけど、距離1だけが実現できない。という感じで、グラフが連結を保つための最低限の辺を残すことに注意しながら、任意の2頂点間を結ぶ辺を K 本取り除けば答えが出る。■提出 #32158282 (AC / 234 Byte)。思いついてから実装完了まで 10 分 15 分でバグも無し。昨日4時間以上苦しんでいたのはなんだったのか。■「という感じで」とか書いて雰囲気で流してしまったけど、星型のハブになる頂点を選びそこに繋がる辺を残すようにうまいこと辺を取り除かないと最短距離2が保証できなくなるっぽい。さっきの提出が AC になったのは頂点ペアの持ち方、取り除き方の2つの偶然が重なった結果なのかも。参考「競プロ参戦記 #53 Friendships | ABC 131 - Qiita


2022年05月29日 (日) [AtCoder] 精進。昨日あった NOMURA プログラミングコンテスト2022(AtCoder Beginner Contest 253)-E,F。E と F が精進の対象だということは4完だったということ。無念なり。現実を直視できなくて結果を見ないまま今日の ARC141 に出たからね。そこで +2 だけ元気をもらって復習にとりかかりました。■E 問題「Distance Sequence」(緑 diff)。とくになんということのない DP のはずだったんだけど、最初の提出 #32032452 が TLE になった。このあと 55 分間迷路に迷い込んでいるうちにコンテストが終了していた。□今日の提出 #32096311 (AC / 727 ms)。ちょこちょこ整理した部分はあるけど本質的な差異は sksk%P かという違い。余りをとるコストをケチってかえって Bignum のコストを支払って TLE になっていたのだった。あほ。■F 問題「Operations on a Matrix」(青 diff)。昨日は問題を読みもしなかった。やることは明らかだけどどう効率的に実装するかという問題。□最初の提出 #32096736 は TLE/MLE になった。長さ 20 万になりうる配列を最大 20 万回複製しようとしていたのだから、40 ギガを数倍したコストが予期される。TLE/MLE も当然。□次の提出 #32097180 で AC。クエリ先読みで必要な値だけ覚えるようにした。典型です。最近では ABC202-E「Count Descendants」を解くときに同じことをした>TLEAC。E 問題を AC してから 50 分だから、%P%P とタイプするだけの手間で E 問題を AC に持って行けていれば6完もありだった。幸せな皮算用。


2022年05月26日 (木) [AtCoder] 精進。ARC103-E「Tr/ee」(青 diff)。まず不可能なケースを考えた。木なので必ず葉があり、葉に繋がる辺を切れば必ず大きさ1の連結成分ができる。S1 が 1 でなければ不可。サンプルにあるように「n 頂点の木から辺を 1 つ取り除いてサイズ n の連結成分を作ることはできません」ので、Sn が 1 の場合も不可。他には、木において辺とは頂点集合を左右2つの連結成分に分けるものなので、Si と Sn-i が食い違う場合も不可。ここから答えの構築を考えた。大きさ1の連結成分から始めて1つずつ大きくして N/2 までの連結成分を作る。N/2 より大きい連結成分は大きさ N/2 以下の連結成分の片割れとして自動的にできあがっているので考えない。Si が 1 の場合、直線状に伸ばすことで大きさ i の連結成分が生じるようにする。Si = 0 の場合、葉を生やして横に大きくすることで大きさ i の連結成分が生じないようにする。最後に余った頂点をすべて葉としてくっつけて始末する。■提出 #31963209 (AC / 403 Byte / 131 ms)。以前に解こうとしたときは、大きさごとに連結成分を分けてプールして、小さい連結成分を組み合わせることでより大きい連結成分をプールするような処理を考えていた。実はプールする連結成分が1つだけでいいことと、大きさ1の連結成分(葉)がすごく便利に使えることに気がついたので今日は解けた。■コメントアウトしてある部分は、解答と入力に矛盾がないことを確かめるために、解答から入力と同形式の文字列を作って比較している。そのために judge.rb27 を書いた。■ブログを読んでいたら、解答のような木には「キャタピラ木 (Caterpillar tree)」という名前がついているらしい。わざわざ名前を付けて区別して嬉しい理由があるのでしょうね(調べない)。