/ 最近 .rdf 追記 設定 本棚

脳log[2024-10-17~]



2024年10月17日 (木) 「ながくのびたいすのかげ(長く伸びた椅子の影)」を「ながぐつのびたいす」と読んだ人がいたなあ。びたいすって何?


2024年10月14日 (月) [AtCoder] お風呂デバッグ完了しました。精進。おとといあった ABC375-F Road Blocked。E 問題が WA/TLE だったのを見てから 21 分で実装したものが WA だった。考える要素がほぼない典型問題でさえ得点できないなら俺の得点源はどこにある?■制約から多重辺なし、自己辺なし。頂点数の制約からワーシャルフロイド法によって全点間距離を求めることができるので、クエリ2に答えるのは一瞬。クエリを逆向きに見れば、辺が不通になるとは辺が新しく利用できるようになること。あるクエリで不通になった辺が以降のクエリでもずっと不通であることはサンプルをよく読んで確かめている。ワーシャルフロイド法をちょっと修正すれば、ある辺を必ず使う場合の最短距離を更新することができる。具体的には3重ループの最外ループが司る中継点を a または b に固定する。順番にやってもいいと思うけど、自分は同時にやった。中継点が a ならコスト c を足して b にワープさせる。逆向きのワープも同様に。そして中の2重ループが司る始点と終点がそれぞれ s と t のとき、D(s,a)+c+D(b,t) もしくは D(s,b)+c+D(a,t) が最短距離の候補になる。D 関数についてはいちいち書かない。■WAAC の差分は1行だけ。新しく利用可能になる直通辺が a-b 間の最短距離であるとは限らないという当たり前のことが抜けていた。どこから勘違いが生まれたのか想像することができる。ワーシャルフロイド法を実行する前、2次元の表 D[N][N] は直通辺だけが記録されたグラフ表現の一種だった。3乗のアルゴリズムを実行することで辺を辿った結果を含む最短距離の表に更新されるのだけど、自分の頭は更新されていなかった。クエリ1を実行するとき D[a][b]==INF だと考えてしまっていた。考えなかったわけではなく、勘違いしていた。無条件に c 書き込んでいいのか一瞬考えて、問題ないと判断していた。■無向グラフにワーシャルフロイド法を使用するとき、ループの回数を半分にすることで TLE の可能性を減らすことができるのは、ABC369-E を通して刻み込んだ学び (20240831)。■C 問題と E 問題についても書きたいけど、まだ解けてないので書けない。■精進2。ARC185-A mod M Game 2 (緑 diff)。すぐにむりむりわからんと投げ出したくなるけど、緑 diff だというのをもう知っているし、テストケースの多さからもシンプルに解けるのがわかる。ちょっとこらえて視覚的に考えてみると (M おきに印が付いた数直線にそって場のカードの和を表す棒グラフが伸びていくイメージ)、そのときどきで出してはいけないカードが高々1枚しかないとわかる。N<M だしね。最後の1枚になるまではどちらも絶対に負けない。2N 枚のカードの数の和で Bob の負けが判定できる。これだけではサンプルが合わなかったのでまだ考える。Bob が最後の1枚を決め打って温存するなら、Alice が N 枚目のカードを出したときの場の和を Bob が N 通り選ぶことができる。その N 通りに M の倍数が含まれるなら Alice を負かすことができる。Bob はその1枚を最後まで温存できるのだろうか。できるに決まってる。出してはいけないカードはあるけど出さなければ負けるカードはない。そんな当たり前のことも確認しなければわからない。提出 #58815966 (AC / 121 Byte)。かけた時間で判断すれば 300 点問題。事前知識を考慮して高めに見積もっても 400 点。<追記>できるに決まってはいなかった。2枚持っていて一方が出してはいけないカードならもう一方を出すしかない。温存できるの?</追記>■精進3。ARC185-B +1 and -1 (水 diff)。右の要素の高さを左に寄せることで右上がりの坂を作る。右に寄せられるなら何の問題にもならないけど、左にしか寄せられない。制約から判断して要素を左から見ていくことにする。二度見三度見は許されない。ネックになるのは、均した結果がある高さになるとしてその右側がへこんでしまうのがいけない。そのへんをうまくやるために4つのパラメータを記録した。すなわち、(現在の要素までの総和、均してもこれより低くできない高さの最大高さ、その位置、その位置までの総和)。提出 #58816249 (WA / 294 Byte)。A 問題から 31 分でまずは WA。提出 #58816379 (AC / 295 Byte)。その修正に 15 分。小なりを小なりイコールに修正した。文字にして初めて思ったけど、なんで小なりと equal がくっついてひとつの言葉を作ってるの?


2024年10月13日 (日) 【悲報】米の値段、下がらない : 暇人\(^o^)/速報 - ライブドアブログ」■お米を経済原理でしか考えられないコメントにもやもやする。米でも芋でも知らんけど、国民を飢えさせないセーフティネットの役割を国には期待している。すべてをアウトソースして海が遮られたらどうなるのか。高ければ食べなければいいではない。それは嗜好品の話だ。飢える人が出ないように生産者を確保して低価格を維持するために補助金を使うのは、目的として真っ当だと思うんだよ。脆弱性を突かれるまでセキュリティが顧みられないみたいなのと似た話なの?


2024年10月12日 (土) ヒゲ剃りにまったくこだわりがない。週一くらいの頻度でお風呂で剃っている。おもちゃみたいな電動シェーバーを使っていたこともあるけど、以後はこれまでのところ使い捨ての T 字がよろしい。高級機はどうか知らないけど、ひょろっと長い1本に対してシェーバーは無力では? 刃は4枚も5枚もいらない。2枚か3枚で足りるし、枚数による違いがそもそもわからない。というわけでスーパーかアマゾンでテキトーに安い6+2本とか8+2本入りみたいなのを買っていたんだけど、この前買い足したものがどうにもよろしくない。初めて使うものではなく前回は特に違和感がなかったので、直前に使っていたものとの違いが使いにくさを感じさせているのだと思う。思い当たるのは2点。1つは刃がぐらぐらなこと。製造不良ではない。たいていの T 字は押せば刃が可動するようになっている。しかし考えてみて欲しい。押せば刃が逃げる状態で、どうして適切な角度、適切な力で刃をヒゲに当てることができるのか。2つ目は同じ2枚刃なのに今のはヘッドが倍くらい大きいこと。刃の上と刃の下の余白が大きすぎる。だだっ広い平面を剃るのではない。あごの曲面をそるのだし、鼻の下を剃るときは鼻が邪魔になる。その余白に意味がありますか。そういうわけなので、これまでのようにテキトーに安い T 字ではなく、ついこの前まで使っていたとりわけ安い T 字であるシック・エグザクタ2を指名買いすることに決めたのでした。以上のことは、自分はヒゲが薄くて何の苦労もしていない、という話なのだと思う。


2024年10月10日 (木) [AtCoder] 精進。先週末あった ABC374-E Sensor Optimization Dilemma 2。「解けるんだからネタバレは嫌だ」とは書いたものの手詰まりだったので、Ruby の AC スクリプトをダウンロードしてきて見つけたダメケースを参考にデバッグをした。■TLE×4TLE×1 のち AC (334 Byte / 1285 ms)。A*B ないし LCM(A,B) の単位では最適な比率が確定するだろうというのが自分の解法の根幹にあったのだけど、そうではなかった。解が W だとして W の周辺 A*B ないし LCM(A,B) の範囲に最適な比率があるというのが正解だった。たぶんね(←それだからお前は……)。TLE×4 の原因は LCM(A,B) ではなくより大きな A*B を使っていたこと。TLE×1 の原因は心当たりが2つあって、1つは二分探索の上限が X によらず一定だったこと。X に依存するようにして最大の場合でも 10 進1桁だけ上限が小さくなるようにした(けど二分探索の回数が3回減るくらいしか期待できなくない?)。2つ目が二分探索の判定を早期に打ち切るようにしたこと。全部を足してから判定するのではなく、累積値がボーダーを超えたらすぐにリターンする。こんなしょうもない定数倍の改善が AC するために求められるのはつらいなあと思ったら、Ruby で提出している他の皆さんは 79 から 931 ms の範囲で AC を出していて、中央値も平均も 120 から 130 ms のあたりにあるみたいだった。自分が桁違いに遅いだけだった。


2024年10月07日 (月) [AtCoder] 精進。おとといあった ABC374-F Shipping。ABC374 を通しての特徴だったけど、制約が 100 以下と小さい。O(N^4) とかにならない限り制約に殺される心配がなかったけど、制約からのメタ読みでアルゴリズムを絞らせない狙いでもあったのだろうか。そしてこの問題は代わりにパラメータが多い。溜まっている注文の数、どの注文まで出荷したか、最終出荷日、不満度の累計。それと最初は気付いていなかったんだけど、最終出荷日というのは Ti の値とは独立して決まるんだよね。何かの注文が出荷可能になったタイミングで必ずしも出荷されるのではない。注文が K+1 個溜まらないように出荷されるのではない。問題を読んで、読むだけでなく理解してください。■提出 #58547000 (AC / 461 Byte / 106 ms)。コメントに書いたように、i 番目の注文を含む 1 から K 個の荷を出荷するような DP を書いた。中心となるデータは最終出荷日と累積不満度のペアの配列。出荷日が遅れるほど不満度は低くなければいけない。逆に言えば、出荷日が早いなら不満度が高くても記録する価値がある。日をおいて改めて考えてお風呂デバッグが完了したと思ったら逆に WA が増えた E 問題と比べると、落ち着いて整理すれば解ける普通の問題だった。■E 問題が解けるまで ABC374 のふりかえりはできないよ。提出一覧で他の人の提出を見たり、順位表で解いている人数を見たり、AtCoder Problems で難易度を見たり、Yahoo!リアルタイム検索で X の投稿を読んだり、ブログの参加記を読んだりできないよ。解けるんだからネタバレは嫌だ。E 問題を始末するまで ABC374 が終わらない。■■■E の精進 (20241010)。


2024年09月30日 (月) [AtCoder] 精進。おとといあった ABC373-F Knapsack with Diminishing Values。X で調和級数とのキーワードを見かけていた。ならば恐れずにやるだけかと思って愚直気味に書いたものは、N のループの中で W のループの中で飛び飛びに W をループするものであって、最大ケース (N=3000、W=3000、wi=1 (i=1..N)) がコードテストで 10 秒以上かかるものだった。飛び飛びに W をループするって書いたけど、重さが1のとき実は飛んでいなかった。調和級数と聞いて勝手に飛んでいる気になっていた。調和級数ってどういう式だっけ? ループひとつの上限? 二重ループの上限?■提出 #58293215 (AC / 510 Byte / 2001 ms)。重さの種類数と品物数が同数ということで、重さにはかなりの程度重複があると想定できる。重複なしにしようとすると重さは1から W の範囲に散らばることになって、重さが W に近づくほど同じ品物を1個までしか選べなくなるという点で好都合になる。だから重複はかなりの程度あると想定する。同じ重さの品物をまとめて扱いましょう。1個選ぶときの最大価値、2個選ぶとき(同じ商品を2個でも別の商品を1個ずつでも)の最大価値……を予め求めておく(6行目から 18 行目)。そうするとループの構造は変わらないけど、最外ループの回数が N から w の種類数に減って AC だった。想定解法かどうかはわからぬ。■Ruby ですでにある AC は l0rzl さんの提出 #58243889 (AC / 1429 ms) のみ。短いし 25 % 速いし、Rational を使ってソートしてるし、これはなんなんだろう。定数倍のハンデがあるにもかかわらず Array でなく Hash を使っていて速いというのは、重さの重複によってキーが限定される効果が大きいんだろうか(だけど w=1 を処理した時点で 0 から W まで全部埋まるよなあ)。優先順位を付けるのは、価値の低い品物が価値の高い品物が一度通った道を再度通らないように、とか? 3重ループの構造は同じ。だけどそれぞれにループの回数を減らす工夫があって違う。■自分のは、どうせ 900 万だからと前処理を愚直にやっているので、そこをサボらずにやる手はある。だけどそうすると元から比較して長かったのがさらに長大化するのが必至。うまくないなあ。しかもプライオリティキューを使っても変わらんかった>提出 #58342271 (AC / 2012 ms)。たしかにメインループの外だから影響は小さいだろうけど、ゼロだとは思わなかった。


2024年09月29日 (日) [AtCoder] 精進。昨日あった ABC373-E How to Win the Election。二分探索なのはすぐにわかる。しかし罠がいくつもあって、時間制限も厳しい。中間獲得票上位 M 人の中に人 i が含まれない場合がまずは考えやすい。その前に正確ではあるけどすんなりは理解できない問題文「i 番目 (1≤i≤N) の候補者はその候補者より多く票を獲得した候補者が M 人未満であるとき、かつその時に限り当選します」について。当落を分ける分岐点がどこにあるかをしっかり把握しなければ二分探索の判定関数が書けない。人 i の得票が上から M 番目の人の得票に並んでいるとき、人 i は当選する。逆にいえば、上位 M 人の全員が人 i の得票を1票でも上回っていれば人 i は落選する。判定関数はこう。答え X を二分探索するとき、X を除いた票を上位 M 人に配って底上げした結果、M 人全員が A[i]+X+1 以上になるなら、判定は偽。落選する。では M 人全員を A[i]+X+1 以上に底上げするのに必要な票数がどう計算できるだろうか。自分は最初 M 人の中間獲得票数の合計と追加票の合計で平均を出すような計算をして間違えた。平均は出さなかったけど、M 人の総得票数だけで考えて間違えた。トップの人が過剰に票を持っていたとしても、その余剰分を底上げにまわすことはできない。じゃあ M 人のうち何人が中間時点で A[i]+X+1 以上の票を持っていたかがわかればそれらの人を除外して累積和で必要な追加票数がわかるね。これは解の二分探索の中でさらに行う二分探索であって TLE だった。提出 #58232088 (TLE×19)。これが 22 時 22 分。昨日のコンテストはここまで。■提出 #58278984 (AC / 456 ms)。解の二分探索をやめました。X 票を人 i を含む M+1 人に分配したとして、底が上位 M 人のどの人とどの人のあいだにあるかを二分探索した。さっきの二重の二分探索の中の方を外に出した感じ。18 行目と 19 行目にある、不可判定(-1)と無条件当選判定(0)であるとか、15 行目と 20 行目にあるボーダーラインの -1 だとか、こちらの解法にはさらに罠が多い。TLE になった log 2つの素直な解法とランダム入力に対する答えを突き合わせてデバッグをした。ま、ボーダーラインの方は目指すべきグラフ(ヒストグラム?)の形がイメージできていたので間違えなかったけど。■提出 #58279635 (C++ / AC / 303 ms)。これは log 2つの、解を二分探索する素直な解法の C++ バージョン。C++ では log^2 が許されていたのだ。■制約に殺されたというにはしっかり難しくて満足できる問題だった。いや実際に制約に殺されてるんだけどね、お前に殺されるなら悔いはない。過去2、3回の経験に加えて今回も言えるんだけど、log 1つの差って、ちょっとした視点の違いなんですよ。ちょっと見る角度を変えれば2つ目の log は消える。これが Pairs の教え (20210401p01)。■■■二分探索を尺取りで置き換えることで計算量のオーダーを改善する常套手段にのっとって、ついに二分探索の log を2つとも取り除いた。提出 #58342253 (AC / 970 Byte / 313 ms)。これでますます制約に殺されたとは言いにくくなるんだけど、これがコンテスト時間内にすらすら書けるなら青といわずとっくに黄色になっている。


2024年09月22日 (日) [AtCoder] 精進。今日あった ARC184-A Appraiser (水 diff)。600 点問題だけど、たぶんインタラクティブ加算が +100 か +200 あるから、実質的な難易度に基づく配点は 400 か 500 あたり。N-1 回クエリできるならすべてのコインを裏表どちらかに分類することができて、もちろん 10 枚だけの方が偽物グループということになる。ところがコイン枚数 N=1000 に対してクエリ上限 Q=950 なので、999 回クエリすることはできない。ところで、1から N までのシャッフルされた順列をソートされた状態にするのに、スワップ回数は必ずしも N-1 回いらないんですよ。N 項が G 個のグループに分かれて、グループ内で玉突きによって位置を交換しているとき、グループのサイズ引く1回の交換でグループ内の要素を目的の位置に置くことができる。全体では N-G 回の交換でソート済みの状態にできる。この問題ではどうか。仮にグループ内の比較のみによって真贋が定まるのであれば、グループをまたいだ比較を節約することができる。グループとは? たとえば 10 回の比較で 11 枚が同種だと判定されたら、その 11 枚は本物に決まる。たとえば 20 回の比較で 21 枚が 10 対 11 に分かれたなら、双方の真贋が決まる。このボーダーは未確認のコインの中に本物と偽物が何枚あるかによって動くし(少ない方+1になる)、選んだコインに偽物が何枚含まれるかという偶然によってもグループのサイズが変動する。最も幸運なケースでは最小 20 回のクエリで 10 枚の偽物を見つけられる。最も不運なケースでは、900 回の比較によって 990 枚の本物を見つけて、消去法で残りの 10 枚が偽物に決まる。最も不運とは書いたけど、終盤は少なくなってきた本物を的確に選んでいるので実は不運ではない。クエリ回数も最大ではないかもしれない。でもクエリ1回につき1個以上の偽物を見つけるとしても見つけられないとしても、900 に +50 回もあれば足りそう。■提出 #58038450 (AC / 1343 Byte / 112 ms)。一番頭を使ったのが 38 行目のボーダーラインを定める式(b = [m,[k-m,10].min].min)。多数派が b より多くなると多数派の真贋が決まるので、即座にグループを閉じて次の要素からまた新しいグループを始める。グループが多いほどグループをまたいだ比較をせずに済んでクエリが節約できる。まだあった。グループを処理する F 関数を実装しているときに、残りの要素の真贋が同数のケースに対処する必要があると思った。未判定コインの中に本物と偽物が同数ある場合。多数派がないからお前が偽物だ(本物だ)と決められない。これはすでに真贋が明らかになっている要素との比較で対処することにした。F 関数の引数 hint がそれ。この対処が実際に必要だったかどうかはわからない。たとえば 890 回のクエリで 979 個の本物を見つけたときに(※10 回のクエリで 11 個の本物が見つけられるのでした)、残りのコインは 10 対 11 であって、問題なく判別できる。残りのコインが9対9になるとか、8対8になるとかのクエリの成り行きが、N=1000,M=10 というパラメータに対して存在しているかどうかはわからない。


2024年09月21日 (土) [AtCoder] 今日はユニークビジョンプログラミングコンテスト2024 秋(ABC372)があった。脳みそがスポンジ化している。このごろは最初に問題をざっと読むんだけど、E までは普通に解けると思って、F 問題に時間をかけて考えて解けるかどうかだと見通しを立ててから A の実装に取りかかった。番狂わせの D 問題。E 問題を終了 20 秒前に提出するのがやっとだった。■A 問題「delete .」。String#tr メソッドは文字の削除もできます。つい最近他の人の提出で見るまで知らなかったけど、String#delete というメソッドもあります。■B 問題「3^A」。N が出力の制約だと気がつくまで時間がかかった。10 万個の数字を出力してもいいんですかと確かめるつもりで問題とサンプル(の上の方)を眺めてもまだわからなかった。制約さえ把握できたらあとは3進数。Integer#digits メソッドは基数を引数に取る。■C 問題「Count ABC Again」。つどカウントするわけにはいかないから、置換前に ABC の一部であればカウントを1減らし、置換後に ABC の一部であればカウントを1増やす。これも実装で下手をして答えが合わなかった。クエリの x を2回使うので、x を変更するのではなく別の変数にコピーしてから変更していたのだけど、最後に別の変数を参照するところで x を使用していた。■D 問題「Buildings」。来ました D 問題。21:26 に C 問題を提出してから 22:25 に D 問題を提出するまでほぼ1時間ぐだぐだやっていた。問題が全然頭に入ってこないの。いったい何を数えるんだよー。問題を完全に理解したのが 22 時 20 分! 理解したら実装は5分。「ビル i とビル j の間にビル j より高いビルが存在しない」という i と j のペアを数えるんだけど、えっとね、i のビルの高さはなんにも関係ないんだよ。サンプル1の解説とサンプル1の出力例を突き合わせて自分の理解の誤りが明らかになったのが 22 時 20 分だったのだ。出力形式もやっかい。合計じゃないんだよ、さりとて j を基準にした数字でもないんだよ。問題を解く筋道を規定されるようでとことん振り回された。解法は後ろから見ていって増加列の列を管理する。いや……ただの増加列なのか。無駄なことをしたかも。■E 問題「K-th Largest Connected Components」。一読してスター型のグラフに殺されるなどうしようかなと考えたときに k が 10 以下との制約が目に入って解けたと思った。連結な頂点のことを隣接頂点だと勘違いしていたのに気がついて途中で UnionFind を(頭の中から)ひっぱり出してきた。連結な頂点に自分自身を数えることも最初はわかっていなかった。Array#max メソッドの戻り値がソート済みではないと知らなかった。そんな感じで実装に 15 分。D 問題のせいで解ける E 問題を落とすのは悔しすぎるので残り 20 秒で間に合って良かった。■F 問題「Teleporting Takahashi 2」。30 分から1時間を残してじっくり考えたかったけど、すべては D 問題のせい。■F 問題。K×N の表を作成していて、K と N がどちらも大きいんだけど、k 行目の値を決めるのに斜めに k 項の和が欲しい。k の2乗はダメだ。左にあって一番近い意味のある頂点が t 個前にあるとして、k-t 番目の値を参照すればいいのかな。■■■F 問題。TLE×8TLE×27TLE×12。なんで最初が一番ましなのか。最初だけ送っていて、あと2つはもらっている。TSP 問題ではもらう方が速いのだけど、逆に遅くなる理由がどこにあるのかわからない。■AC! でも Ruby の他の提出では全部で4つの AC がいずれも 1500 ms 前後しかかけていない。自分のはやっとで 2055 ms。25 % 遅い。正直なにが AC と TLE を分けたのかもわかっていない。他の人の提出を読んだ(眺めた)けど、なんか遷移がシンプルだよね。DP のために用意する配列のサイズが N+K だったり N から継ぎ足して N+K だったり、最初から最後まで N だったりもする。自分は 2M×K の2次元配列(※)を使った。明らかに何かが違って効率が悪い。むむむ。※ C 言語では2次元配列と配列の配列(jagged array)を区別するけど、Ruby には片方しかないので……。■たぶんだけど、ある頂点の場合の数を記録している添字をずらしていくことで1つ先への移動をノーコストで行うんだと思う。初期にはそういうことも考えていたけど、移動したら移動元には場合の数が残らないはずなのに、考え違いをしていて一歩ずつ加算していかなければいけないような気がしていた。今日も実装を始めたときにはまだその勘違いをしていて、過大な答えが出たりしていた。勘違いで解法を潰してしまっていた。提出 #58036342 (AC / 1430 ms)。ほらね、1500 ms グループの仲間入り。提出の中でなんで y から x を引いてまた x を足してるのかはわかりません。差分が生きるような気がしたけど、気の迷いだった。


2024年09月19日 (木) [AtCoder] 精進。CodeQUEEN 2024 決勝の FG。E までしか解けなかった 20240823 の続き。時間をおくと勝手に解けるメソッド。なお、その時間が余命より短いか長いかはわかりません。■F 問題「Divide the Cake」。円環に切れ目ということで前々回の ABC370-F Cake Division を思い出す。ダブリングで解けるかなと考えてみるけど、解けない。どういう問題か。切れ目を1つ選んだとき、その切れ目から1切れ、2切れ、……、N-1 切れのまとまりのいずれもが、1切れあたりの平均において全体の平均を下回らないような、そういう切れ目を見つける。問題には選ばれなかった残りのピースの平均との比較が書いてあるけど、全体の平均と比較するのと同じことでしょう。平均をどう扱うか。累積和を1で割ってみたり2で割ってみたり3で割ってみたりするようでは O(N^2) になってしまう。濃度の二分探索では必要な溶質の質量との差分で考える。平均との差分の累積和を考えてみる。1切れの和、2切れの和、……、N-1 切れの和までの N-1 項の累積和のいずれもが0以上なら、どういう切り方をしても平均を下回ることがない。2周分の累積和をセグメント木に乗せて、N 回、N-1 幅の区間最小値を尋ねた。平均を考えるのに小数は使いたくないから、N で割る代わりに乗ってる数を N 倍した。そうすると全体の平均は元々の数の総和になる。それとの差分の累積和を考える。提出 #57894314 (AC / 636 Byte / 596 ms)。■G 問題「Quintuple Scoop Ice Cream」。二分探索っぽさがあるよね。衝撃の青 diff だった ABC227-D Project Planning みたいに、うまく判定する方法があるのではないか。わからないけど。あるフレーバーを選べる上限は 3K 個まで(1段目と3段目と5段目に)。1つのフレーバーを 3K 選んでしまったら、他のフレーバーは 2K までしか選べない。どのフレーバーも 2K 個までは何も考えずに使えるとも言える。2K を超えるフレーバーが1種類だけだったら、追加で K 個まで使える。2種類以上あったら……全部合わせて K 個まで追加できる。あとは使えるだけ使い切って 5K に足りているかどうかで判定する。提出 #57906057 (AC / 723 Byte / 351 ms)。判定するだけではなかった。トッピング例を構成しなければいけない。ABC362-F Perfect Matching on a Tree の解答を構成するのにプライオリティキューみたいな道具が必要ないように(20240713)、K 個ずつ5段にうまく並べたいと思ったけど、すっきりきれいにはできなかった。5段目を置くときに同じトッピングが最大で3個になるんだけど、必ずしも (A,B,A,C,A) にはならなくて、(A,B,C,A,A) とか (B,A,C,A,A) みたいなケースが考えられる。K 行に渡って泥臭く並べ替えた。■最後の H 問題はまだ。


2024年09月18日 (水) 自分ルールというものがある。自分のやることはたとえば8割が決まっていて(あれの場所はここ、これの順番はこう、こういうことはしない、などなど)、2割がどうでもよかったりする。そして他人。他の人にも守ってほしい譲れないルールというのは、多くても2割ほどではないか。そうすると全体の8割がどうでもいいことだということになる。2対6対2が、8対2になったり2対8になったりする。これをうっかりいつでも8対2にしてしまうと、8割のルールを押しつけようとしてしまうと、突き詰めれば「他人は自分ではない」という不満を常に抱き続けることになる。他人が他人として、尊重すべき別の個として見えていないとそうなる。強力な連帯感で結びついた集団の強さもあるかと思う。その幻想がまったく共有できないことは、しようのないことなのです。


2024年09月14日 (土) [AtCoder] 今日は AtCoder Beginner Contest 371 があった。今日も冴えなかった。C も D も E もやるだけのはずだけど、正しく実装できない。それぞれ 34 分、8分、21 分かけている。そして F もやるだけではある。ややこしいし時間が足りないし、X の制約のせいで BIT に SortedSet の代わりをさせることができなくて TLE を避ける方法がわからないけども。■A 問題「Jiro」。ABC のそれぞれを中心に置いて比較結果を並べたときに << もしくは >> になっているかどうか。これも4、5分かけたんだよね。どうにもすっきり実装できなかった。ソート関数に比較関数を渡すことも考えたけどやらなかった。他の人の提出を見ると、入力から2つを2回選んで比較するだけで答えが出せるみたい。■B 問題「Taro」。b=='F' は無視する。b=='M' のとき a が最初かどうか。これも実装で下手をして次男にも Yes と答えていた。■C 問題「Make Isomorphic」。N の制約が8以下ということで、8!*8*8/2 小なり 130 万なので頂点番号の入れ替えを全通り試すだけ。答えが合わなくてずーっとあれこれしていて、ついに明らかになった原因は、辺の操作コスト A を受け取るときに -1 していたことだった。勝手にコストを減らしてはいけない(二度と役に立たない戒め)。頂点番号を0始まりに補正するコードに引きずられて、コピペでもないのにマイナスしていた。グラフが2つと三角形のコスト表という、入力を受け取るのが一番難しい問題だった。■D 問題「1D Country」。累積和と二分探索。これ D 問題かなあ。二分探索の境界のイコールの有無と、数列の添字と累積和の添字の区別に注意をする。こういうことをどこかで読んだことはないんだけど、C++ の2種類の二分探索が lower_bound と upper_bound なのって、イテレータの半開区間の下限がイコール付きで上限がイコールなしなのを踏まえた命名であって、本来それだけの意味しかないよね? C++ を離れたら通じないよね?■E 問題「I Hate Sigma Problems」。主客転倒で数字ごとに寄与する範囲の数を数える。ここまで 20 秒かからないのに結局 21 分かけてるのはなんで? 2つ目のシグマが j=i から始まってると認識したのが遅かった。そこからはまともに範囲の選び方を考える(考え直す)ことができなかった。範囲の選び方が N*N かな N*(N-1)/2 かな N*(N+1)/2 かなと定まらないのは 20240831 とまったく同じ展開。他には余事象を試してみたり、答えが合わないせいでいつまでも思いつく限りのテキトーをやっていた。愚かだ。■F 問題「Takahashi in Narrow Road」。集団を寄せて移動するのは ABC365-F Takahashi on Grid を思い起こさせる。違うのは集団の中ほどで分裂することがあることかな。それでも集団の数は N 個を超えないし、クエリごとに集団の数が0個以上減る一方、増える数は最大で1個なので、ソートした状態で集団(端の位置、幅(=数)、累積数)の管理ができれば良さそう。併合分裂は N+Q のオーダー。でも道具がない。X の値域が広いために BIT で管理するためにはとりうる値が予め列挙できなければいけないが、できない。■■■予め値を列挙しておかなくても自動的になんとかしてくれる BITSet を盆栽したけども、普通に BIT を使う場合より 2.5 倍くらい遅くなった。たとえば制限時間5秒の問題 ABC365-F への提出で 2675 ms かかっている #56361608 が 2.5 倍遅くなると TLE になるんだよね。ABC371-F への Ruby での提出が未だゼロなのは、つまり、あきらめなのですか? 制限時間3秒だしなあ。■■■F 問題。提出 #57862947 (Ruby / TLE×3)。普通に配列の要素を削除・挿入しただけだけど、35 ケースは通った。TLE のケースが実際にどれだけかかるのか、4秒なのか、30 秒なのか。C++ で map を使ったものは 289 ms で通った>提出 #57864113 (C++ / AC)。C++ で提出時刻が早いものを見てると、LazySegtree を使うものが多いみたい。それはどういう解法か……。■F 問題。Ruby で通った! 提出 #57872364 (Ruby / AC / 1772 Byte / 1047 ms)。値が大きいから座標は BIT の添字にできないけど、累積人数を BIT の添字にすることはできる。N=9 だとして、座標左から 2,3,4 人の3つの集団があるとすると、BIT の 0 から N+1 の範囲に 0,2,2,5,5,5,9,9,9,9,10 という値を記録する。両端は番兵(提出コードで番兵を使っていないのは(69 行目と 86 行目)、バグがあると番兵が機能しないからなのですね。普通に処理対象にされて削除されてしまう番兵さん……)。座標は累積人数(2,5,9)を添字にして配列から引く。BIT 上の二分探索で隣の集団を見つけることができるけど、対数時間がかかるのをケチってこれも配列(Pv,Nx)に記録した。なんとかなってしまうものだなあ。そうするとコンテストで通せないのは精進が足りないせいってことになる。それは……つらい。■実は累積人数をキーにする発想は C++ で map を利用するときに必要に迫られて出て来たものだった。最初は、座標をキーにしてソートしておきながら、値のひとつである累積人数を参照して二分探索をしたいと思っていたが( T 番目の高橋くんを見つけるために)、そういうことをする比較関数を渡すことはできなかった。それは当たり前の話で、キーについてソートされているなら、キーについてしか二分探索はできない。値である累積人数で二分探索できると思ったのは、座標でソートした結果が累積人数でソートした結果と同じだと知っていたからで、だけど座標をキーにするのも累積人数をキーにするのも同じことだとはまだ気がついていなかった。■■■F 問題。LazySegtree で解いていた何人かが座標を補正することで高橋くんの幅をゼロにしているようだった。なんのこっちゃ。たとえば t 番目の高橋くんが座標 g に移動するとき、t+1 番目の高橋くんは g+1 を下限とするように、t+2 番目の高橋くんは g+2 を下限とするように移動しなければいけないし、逆を見れば t-1 番目の高橋くんは g-1 を上限とするように、t-2 番目の高橋くんは g-2 を上限とするように移動しなければいけないのだけど、t 番目というのを座標に織り込んでしまうことで、全員が同じ座標を目指すことができる。これは BIT を使う場合にも嬉しいことがあって、座標の数が N+Q 個に絞られるので座標圧縮ができる。提出 #57916028 (AC / 1503 Byte / 1366 ms)。最初の提出よりやや短く素直に実装できてるけど、座標の補正(35 行目と 41 行目)がややこしい。特に目的地の補正の必要性と、どう補正するかが、なかなかわからなかった。要するに、今やっとわかったけど、1人目の高橋くんだった~という座標に初期位置をずらし、1人目の高橋くんだったら~という座標に目的地をずらしているのだ。こういうテクニックは過去に2回利用したことがあり、そのときはポテンシャル云々と勝手に呼んでいたけど、今回のように目的とメリットが見えにくいなかで発想するのは難しい。実際に座圧できるというメリットがあったんだけど、テクニックを提示されてさえすぐにそうとは気付けなかった。