/ 最近 .rdf 追記 設定 本棚

脳log[2023-04-14~]



2023年04月14日 (金) 20230309 にも書いたけど『人はどこまで合理的か?』(スティーブン ピンカー)をまだ読んでいる。今は下巻。基準率(base rate)という単語をこの本以外でも見かけるようになったけど(つい先日もツイッターで)、単に本で読んで知ったから目に付くようになっただけで、以前からあったのかもしれない。過去に読み始めたものの頓挫してる『データ解析のための統計モデリング入門 : 一般化線形モデル・階層ベイズモデル・MCMC』(久保 拓弥)を思い出させる内容もあって、なかなか厳しい。読み物ではあるけども。■またしても言葉について。下巻の 194 ページから、対立軸を例示して「たとえば階層主義か平等主義か、自由主義か共同体主義か、王冠と祭壇か啓蒙主義か、部族主義か世界主義か、悲劇的ヴィジョンかユートピア的ヴィジョンか、名誉を重んじる文化か尊厳を重んじる文化か、集団志向の道徳的基盤か個人志向の道徳的基盤かなど。」とあるが、名誉と尊厳の対立がよくわからなかった。これって同じ側の言葉に見える。思いつく原語は honor と dignity あたりなんだけど、日本語の意味が十分に掴めていないか、日本語にするときに重要なニュアンスが消えてしまっているか、なんにせよ理解が曖昧な部分があるとわかって気になってしまった。雰囲気で違いをでっちあげると、名誉は外から贈られるもので、尊厳は内から出てくるものかなと思ったけど、これまでそういう風に考えたことはないし、それが対立する状況も想像できない。こういうのに答えるの、ChatGPT が得意な分野という気がする。実際の使われ方から意味にあたるものを抽出すること。■■■@2023-04-26 別の本だけど『ファスト&スロー』(ダニエル カーネマン)の上巻 102 ページから、プライミング効果に関する内容だけどそのことではなくて例示されたものについて。「世界には、ひんぱんに尊敬を思い起こさせる文化もあれば、神を思い出させる文化もある。また、「親愛なる指導者」の大きな写真を使って、服従というプライムを国民に与える国もある。」 先々週(14日)に書いたように名誉と尊厳の対比はよくわからなかったけど、この本に書かれている2者+1は、人を上に置くか人の及ばないもの(神)を上に置くかという違いで理解してもいいだろうか。尊敬という一語だけで対象を人に限定してしまう用法に違和感があったけど、明鏡国語辞典によれば「「尊敬」は多く人間とその行為に限られるが、「敬う」は、尊い存在として敬意を払うべき高位のものに及ぶ(恩師[祖先・神仏]を敬う)。「崇める」は、敬うべき絶対的な存在に向けられることが多い(釈尊[神仏・太陽]を崇める)。」とあるのでむしろそういうものらしい。ひょっとしたら2つの本は同じことを指しているのかもしれないと思った。名誉=尊敬、尊厳=神威。無理か? それはそれとして、人と神の対比は、神格化される人がいたり神を代弁する人がいたりして曖昧に感じる。それよりも、人であるか神であるかにかかわらず自分の上に他者を置く心性、分を弁え身を修め奉仕する心のありようが共通していると思った。日本人が外国人に対して「無宗教です」と伝えるつもりで「無神論者です」と伝わってしまってやべー奴だと誤解されてしまうというエピソードがしばしば語られるけど、無神論者のやばさって、そういう心性の欠如として理解すればいいのだろうか。アナーキストに近い概念だと説明されることがあるけど、無宗教・無神論に対するイメージが実はよくわからない。無というよりは反で、反宗教的な活動家、みたいな?


2023年04月13日 (木) [AtCoder] 精進。20230409 に書いたように ABC123-D「Cake 123」(水 diff)。難しかった。ABC197-E「Kth Takoyaki Set」と似ているということで解法の見当がついた状態で挑んだけど、ひとひねりあって考えてしまった。制約を比較すると N の上限が 10 から 1000 へと増えている一方 K が 20 万から 3000 に減っている。列が3本あるのも違いだけど、それは最初に2本を組み合わせてソートして 100 万のソート列と 1000 の「値を増加させるプロセス」に転換できる。O(NK) が通る制約なのは同じだから、ここから同じ解法で答えが出る。じゃあどこに考え込む要素があるのか。プログラミングをする者の思考として共通部分を見つけて括りだしてまとめる傾向があると思う。100 万のソート列と 1000 のプロセスを組み合わせて K 個の値を大きい方から作り出す本処理を書いたとき、前処理で行った 1000 の列を2本組み合わせて 100 万のソート列を作り出す処理にも応用できないかと考えてしまった。一見できそうに思える。なんなら本処理よりも簡単にできそうに思える。というのも本処理では 100 万と 1000 を組み合わせるので迂闊に全体を一括して扱うと 10 億になって手に負えなくなる一方、前処理では 1000×1000 = 100 万なので雑に組み合わせて全体を一括処理して構わない。それなのに本処理と同じやりかたを前処理に適用しようとして N の3乗 TLE になりそうなことに気がついて、なんでそうなってしまうのか考え込んでしまった。■提出 #40551459 (AC / 267 Byte / 748 ms)。前処理と本処理を共通 M (マージ)関数にまとめることはできなかった。■Ruby によるすべての提出を見ると2桁 ms の AC がいっぱいある。自分の解法は ABC297-E の制約を見て考え出されたものであって、ABC123-D 向けには別の解法を採用すべきだったということ。ちなみに ABC297-E には他にプライオリティキュー解法と二分探索解法が存在している。自分が過去に ABC123-D で WA を出した解法は二分探索解法だった。もうすこし考えねばならぬ。■前処理で作成するソート列の長さを制限することができる。そうするとさっき書いたことに反して共通のマージ処理を使うことができる。2桁 ms の提出は長いものと短いものに二分できるみたい。長いものはプライオリティキュー解法で、短いものはソート済みであることを踏まえて賢く打ち切りながらの全列挙だった。


2023年04月12日 (水) 【画像あり】流石のお前らでも文句のつけどころがない天丼が発見されるwwwwwww : 暇人\(^o^)/速報 - ライブドアブログ」■エビイカは鉄板でいいね。でも案外エビがダメな人は多いね。あなごよりキスの方が癖がなくて嬉しいかな。ホタテがあると最高。ナスがないのはいただけない。中に含んだ水分が貴重なオアシスなので。他はお好きに、どうでもいい。だけどこれも案外に、玉子が好きな人は多いみたいだね。野菜を足すなら甘くて柔らかいカボチャがいい。


2023年04月11日 (火) [AtCoder]「AtCoderさんへ 有理数ジャッジを使う際に mod 998244353 で合同な整数を全部ACにするのをスタンダードにして浸透させましょう 今日のCF-D1Dのような悲劇が防げます どうかお願いします 物理好きより」■リプライにある Yes と YES と YeS とか余分なスペースとかについてまずは。たいていの言語は識別子の大文字小文字を区別するし自分が書くときにそこをいい加減にすることはないんだけど、では受け取るジャッジがどうあるのがベターかというと、そこは答えの本質ではないしあえて WA として切り捨てるほどの違いでもないかなと思う。メイリオあたりから全角数字へのアレルギーがなくなった者並の感想。何か、区別させたい人って国語のではなかったりするテストで漢字のトメハネハライくっつけるはなすの違いに赤ペンでチェックを入れる小学校の先生とダブる。Twitter でそういう画像が上がると「正解だろ」「国語のテストじゃないのに」って意見が目立つけど、自分は違いを知っていて崩すのと最初から区別する目を養う機会を奪われているのでは全然違うと思うし、小学校の先生って教科担当ってわけではないから、いまどきそういう手間暇をかけた指導はありがたく感謝していいと思う。立場がブレてますけども。意味のある違いかという判断が人と状況によって分かれるってことなんだろう。答えは出ない。でも判断が分かれるところで区別できないこと気がつけないことは不幸だと思う。そのことにどういう姿勢で臨むか。(問題ごとに異なるにせよ基本的に) ABC で区別されていて ARC/AGC で区別されていないらしいというのを初めて知ったんだけど、その違いに説明は付けられる。■mod について。直近の ABC297-F では「得られるスコアの期待値を mod 998244353 で求めてください。」という問題文の直後に折りたたまれて補足説明的な感じで「(前略) R×Q≡P(mod 998244353) かつ 0≤R<998244353 を満たす整数 R がただ一つ存在することが証明できます。この R を求めてください。」と書かれていて、答えの範囲が疑問の余地なく書かれてはいるんだけど、mod 998244353 で求めてください、という本文に立ち返ると 3 (mod 2) って 1 (mod 2) のことではなくて 2 を法とするとき 3 と 1 が区別されないってことなので、998244353 以上の答えがなんで間違いになるのかなという気持ちになる。一方で、OLE という最レアジャッジがあるので無制限にリソースを奪われる心配もないはずだけど、ジャッジのコストやプログラミング言語の整数型サイズなど現実的な判断として 0≤R<998244353 の範囲で一意に決まる数(R)を答えてくださいという要請も理解できる。ただし真の値を 32 ビットの範囲に丸める便宜的な(本来の意味で姑息な)やり方ではあると承知していていい。最近読んだ「新しくプログラミング言語を作る際に数値型をどうするべきか」みたいな話で、今の当たり前がいつまでも当たり前ではないと思うし、ましてや今の当たり前から外れることが「キモい」なんてことはないはず。


2023年04月09日 (日) [AtCoder] 今日は ABC297 があった。自分のすべての提出コンテスト成績証。DEF 問題について書く。■D 問題「Count Subtractions」(灰! diff)。数学問題苦手。でもまあ、エラトステネスのふるい……じゃねーや、ユークリッドの互除法の名前は忘れてたけどどういう処理かは精進(20191118p01, #8508807)のおかげで知ってますよ。Ruby 2.3 の頃は余り付きの pow メソッドがないから逆元の計算に苦労したのだ。■E 問題「Kth Takoyaki Set」(緑 diff)。N≦10 が特徴的な制約。10 個以下の数を重複ありで組み合わせて K 個の数を作りたい。効率的にソート列を伸ばしていく方法は。たとえば値を増加させるプロセスが1つだけなら、与えられたソート列と、処理済みのソート列の2本の配列を持って、2つの配列の先頭の要素を見比べて小さい方の値を取り出して処理して処理済みのソート列の末尾に追加することでソート列をどんどん伸ばしていける。それは 20190916p01.0120220129p01.06 に書いた。今日の問題への応用は。(1)1本のソート列に 10 のプロセスが張り付いて次の値を提案する。(2)ふさわしい値をソート列の末尾に追加する。(3)次の値を提案するために各プロセスがソート列上を少し後ろに移動する。という感じ。提出したスクリプト8行目の while 修飾子は if 修飾子で十分だった気がする。提案した値が採用されたプロセスだけが添字を +1 するだけのはずだから。Ruby でプライオリティキューは定数倍の重さが致命的になりがちでできるなら避けたいところ。■F 問題「Minimum Bounding Box 2」(青 diff)。類題を何問か解いている。「Black and White Rooks」(20220306) と「AtCoder社の冬」(20211222)。だから処理の流れはわかったうえで、TLE にならないように同じ数え上げを省く効率化を間違えずにやることに専念して、1時間以上苦しんだ。全部を一度にやるのは難しいから、全然答えが合わなくてそれを痛感したから、愚直解を書いて答えを合わせてから、その式をにらみながらリファクタリングをするようにした。最初に行方向の数え上げだけを効率化して提出してみたけどきっちり TLE になったので、残ったわずかな時間で列方向の数え上げも効率化してぎりぎり(2つの意味で)時間内に間に合った。「けっこう制約が優しくて、ループ内で愚直にスキャンして掛けて足し合わせても間に合いそう」だった先の2問よりも厳しい。厳しいのになんで黄 diff より下の青 diff 止まりなのか。水色の自分が通しているからか。■E 問題が Cake 123 に似てるというツイートを読んだけど、自分はその問題は WA で投げ出している。これが次の精進候補かな。■■■@2023-04-12 F 問題。解説の方法でやってみた。提出 #40569324 (AC / 508 Byte / 812 ms)。なにこれ簡単。h×w の枠を H×W の内部で動かすとか、累積和で DP を高速化するとか、まるで関係ない。足して引いて足して割るだけ。なにそれずるい。■もうひとつの解説のやり方もやってみた。提出 #40569949 (AC / 644 Byte / 1081 ms)。この形は見覚えがあるなあ。AtCoder社の冬への自分の提出 #28054417 だなあ。こちらは枠を動かすステップがあるけどそれでもまだ簡単だなあ。ずるい。ループを通して相殺される足し引きを予めまとめておかないと間に合わないくらいの努力が要求されたんだよ、最初の提出(#40491985)では。


2023年04月05日 (水) [AtCoder] 精進。ABC296-G「Polygon and Points」(黄 diff)。やることはすぐにわかるんよ。頂点を1つ起点に選んで他の頂点を眺める。クエリで与えられた点がどの頂点と頂点のあいだにあるのかを二分探索で調べる。あとは見つけた隣接2頂点が張る辺と点の前後関係で答えが出る。しかしそれをきっちり誤りなく行うのが難しくて 6WA を重ねてしまった。■提出 #40344048 (AC / 707 Byte / 2244 ms)。冒頭に3つの関数がある。放射線内?直線上?外部?。1つ前の提出 #40337287 (WA×3) を見るとそれらは 線上?内部? だった。ちなみに2つ前の提出 #40336676 は WA×2 だからいじって逆に WA を1つ増やしている。その差分から直線と線分の区別があいまいだったことに気が付いたし、その他の原因は便宜上の三角形を用いた内/外/境界線上判定が解答の IN/OUT/ON と1対1対応してはいないこと(三角形の辺が多角形の輪郭線と一致している場合と一致していない場合で分かれる)と、道具に選んだ Complex(複素数) の取り扱い方が不確かだったことだった。1点を原点に選んであれやこれやする、1辺を基準に選んであれやこれやする、というので迷走したし、原点に選んだ1点と (0,0) の区別を間違えたりもした。外積って (a.conj*b).imag で求まるんだなーというのも今回の発見。ただただ幾何判定への正確な理解と正確に実装する力がなかった。■あ、線上?直線上? に改名したときに絶対値の比較をやめるべきだった。まーだ、実装に間違いがある。あと細かい話だけど、内部?not 外部? で置き換えたのは、内部と線上を区別しないように書き換えた 内部もしくは線上? 関数より 外部? 関数の方が(問題から離れて)単体で見たときに有用だと思ったからなんだけど、だったら 放射線内?(線上を含んでいる) も not 放射線外? として用意すべきだった。不徹底。■ローカルでランダムテストケースを作ろうとすると狭義凸多角形の部分で困るよね。±10 の XY 平面に三角形か四角形をテキトーに拡大して配置して全格子点 441 個をクエリにしてテストした。■CP(外積)、上方?下方?線上? の語彙を使って整理した。提出 #40350677 (AC / 606 Byte / 2254 ms)。a.conj*b って内積も外積も求まるのんな。たぶん複素数って一般性が足りないと思うんだけど(自分は不足を感じられるほど先を知らないけど)、おかげで目的に合致しているとすごく扱いやすいと思う。と、その扱いにすら難儀していた者が申しております。■『デモクリトスと量子計算』(スコット アーロンソン)という本を読んでいたら文字を目でなぞっていたら「代数的に閉じている」という言い回しを見かけたけども、複素数の位置づけの実際のところってどうなんでしょうね。


2023年04月04日 (火) 人はこうして見る目を養っていくのだ。あなたは味のしない苺を食べたことがありますか。私は今日初めて食べました(幸運の終わり)。甘くも酸っぱくもない、水だった。おいしくない水だった。赤丸ほっぺのアホづらが見える。クマが憎い。今シーズンはもう終わっていたんだな。■終わった……? 「[B! 果物] 米紙の疑問「日本では、なぜイチゴが冬にとれるのか?」 本当は「春の果物」なのに… | 高すぎる環境負荷と市場のニーズの間で揺れるイチゴ農家


2023年04月03日 (月) [AtCoder] 精進。パ研合宿2022 第2日「パ研杯」-C「Collaboration」。基本的な解答方針はすぐに見える。階差の最小値はセグメント木に聞けばいい。クエリで与えられる2つの範囲の値域が重ならないなら A 列の階差を乗せたセグメント木と B 列の階差を乗せたセグメント木にそれぞれ尋ねて小さい方を答えにする。範囲が重なっているなら加えて A 列と B 列を混ぜてソートした C 列の階差を乗せたセグメント木にも尋ねる。基本的にはこれで答えが出る。なかなか消えない WA の原因は交差する範囲に隣接する(一方の範囲にだけ入っている)要素の取り扱いにあった。それから A 列と B 列に等しい値が存在する場合も C 列内でうまく序列が付けられなくて扱いが難しかった。4WA するあいだに (818 Byte / 2217 ms) だったものが (1196 Byte / 3313 ms over) になり、やっと WA が解消しても TLE だった>提出 #40299812 (TLE×10 / 1331 Byte / 3312 ms) ■提出 #40310343 (AC / 1257 Byte / 2457 ms)。二分探索を省くために前処理することも考えたけど、ローカルで作成した最大ケースでは逆効果だったので二分探索は残してある。逆に二分探索があるから IA/IB というデータが省けた。あとは細々と、&:to_i_1.to_i にしたり、2要素の配列を要素に持つ Hash を2つの Hash に分けたり。蓋を開けてみれば 500 ms の余裕をもっての AC だった。■つぎは day1-H「Attack Survival」への提出 #40291192 が 21 ms over で TLE×1 なのをなんとかしたい。たった 21 ms ではあるけど、ジャッジサーバーで慎重に繰り返し実行してそれでも TLE だったということなので、いじって出し直すと逆に悪化したりする。解答の方針を転換する妙案もなく。


2023年03月31日 (金) [AtCoder] 精進。Sky株式会社プログラミングコンテスト2023(AtCoder Beginner Contest 289)-F「Teleporter Takahashi」(黄 diff)。とにかく取っ掛かりが見つからなかった問題。今日の最初の気付きは X 座標と Y 座標を分離して考えていいのではないかということ。X 座標に限定して考えてみる。グリッドを軸として線対称の位置にしか移動できないので、始点と終点の偶奇が一致していないと絶対に辿り着けないことがわかる。次は1差の2点を順番に使用することで±2単位で移動していけることがわかる。±2という最小単位の移動を繰り返しても許される制約になっていることを確認した。あとはまあ細々(こまごま)と、長方形 R が小さすぎて1差の2点が利用できない場合や、利用できそうに見えて実は始点と一致しているために有効に利用できない場合に注意して。■提出 #40189807 (AC / 781 Byte / 502 ms)。非常に気持ちのいい AC。解けて嬉しい。テストケースがまだ利用できないんだけど、最初の提出 #40189747 が WA×2/TLE×10 だったときは一瞬絶望しかけたよね。サンプル3を通すための 6,7 行目のハック(<<x<<y)が雑だったのと、11 行目の判定が早すぎて 15 行目の前にあるのが良くなかった。たった2要素を得るために 20 万要素の配列を作るのが憚られたので Enumerable#lazy メソッドを初めて使ったよ。■「利用できそうに見えて実は始点と一致しているために有効に利用できない場合に注意して」 嘘だよね。長方形 R に2つきりしかない1差の2点の X 座標(Y 座標)の一方が始点の X 座標(Y 座標)と一致していても±2ずつ移動していけるよね。早とちりで No と答えてる気がするけど、テストケースの甘さに助けられたのか?■まだちょびっとだけ理解が及んでいない部分があるらしい。提出 #40200554 (WA×1)。長方形 R の縦と横の長さを最大限に利用して終点を目指してみたのだけど、1つだけ WA になってしまった。どこに考え漏らしがあるというのか。AC はやはり偶然だったのか。■いいや、大丈夫。完璧だ。提出 #40201186 (AC / 506 Byte / 377 ms)。3行目の SY を SX と間違えていたうっかりミスが 1WA の原因だった。考え漏らしはナシ! 十分に整理して満足のいくスクリプトになった。


2023年03月27日 (月) [AtCoder] 精進。ABC228-E「Integer Sequence Fair」(水 diff)。以前に WA を出している>提出 #36786504 (WA×15)。今日改めて取り組んでみて書いたものが図らずもその WA 解答と一字一句同じだった(違ったのは空行が1つあるかないかだけ)。まるで成長していない……。■提出 #40106188 (AC / 92 Byte / 66 ms)。テストケースを利用しました。どうやら良くなかったのは mod を取った累乗を指数にしてまた累乗を計算したことらしい(mod を取らずに指数にする累乗を計算したら AC と解答不能に分かれたので)。足し算引き算掛け算は mod 付きでも自由にできるけど、割り算はちょっと制限があって、そして累乗もそのままではできないらしい。がちゃがちゃデバッグをやりました。逆元の計算でおなじみフェルマーの小定理があるじゃないですか。勘違いして最初は P-2 を mod にしたのだけど、P-1 にすると具合がいいようだった。だけどときどき間違える。そういうのはだいたい全か無か、P か P-1 か 0 かという違いですよ(「悲しさを考える前にまず m で割った n 個の余りについて考える。(中略)。余りが 0 の項の悲しさが 0 であることに注意して……」)。というわけで 0 に目を付けて P-1 に補正したらうまくいきましたね。こんなんで AC をとっても身にならないね!■「勘違いして最初は P-2 を mod にしたのだけど、P-1 にすると具合がいいようだった。」 勘違いしていたというのが勘違いだったみたいで、モジュラ逆数を計算するなら P-2 乗で間違いない。P-2、P-1、P 乗がそれぞれ 1/A、1、A に対応する雰囲気。


2023年03月26日 (日) [AtCoder] 精進1。昨日あった ABC295-D「Three Days Ago」(緑 diff)。いやあ、これ難しいよ。一日置いてもまだ考えたもんね。組み合わせを考える N^2 の処理が許されないから、右端を決め打って右端にある文字に応じて決まる嬉しい文字列の左端を数えることが許されない。よね?■提出 #40082295 (AC / 116 Byte / 145 ms)。昨日には訪れなかったひらめきはこう。文字列の先頭からの累積で 0-9 の数字の出現数の偶奇を記録する。状態数 1024。そのビットパターンの出現数を記録する。たとえば 10 文字目までの累積でビットパターンが 0b1010011000 になったとする。そしてこれまでに 4 文字目までの累積と 6 文字目までの累積でも同じビットパターンが出現していたとする。すると (l,r) = (4,10),(6,10) が嬉しい文字列としてカウントできる。これって全然明らかではないよ。1文字目からの累積状態を記録していく。数えるのは現在の累積状態と同じ状態の数。知りたいのは区間の状態だけど先頭からの状態と状態を比較する。前回の ABC-G について書いた「根からの距離がわかると2頂点間の距離がわかるか? 「頂点 1 からのパスによって決まる値だけを考えて答えを出していい理由は、たぶん LCA までのパスが相殺されるからとか?」からの連想で、LCA を使って引き算すれば求められる気がした」。これと同じレベルの考察だと思うよ。ABC294-GARC045-C と同じ。でもまあ、解かれたからの緑 diff 下位なんだけど。しかたない、AtCoder には自分を除いて天才しかいない。■■■精進2。ABC232-F「Simple Operations on Sequence」(青 diff)。以前は TLE だった。N≦18 という制約を見て2週間前の精進を思い出す。「順列総当たりが許されない制約(N≦16)だけど、A<B、A>B を区別せずに2回目以降の数え上げがサボれるなら許される」。提出 #40085558 (AC / 1181 ms)。はい、許されました。


2023年03月25日 (土) [AtCoder] 精進。今日あった ABC295-G「Minimum Reachable City」(黄 diff)。有向グラフがあって、最初は1番の頂点を除いて小さい頂点から自身に向かう辺がある。つまり、ある頂点は自分より大きい頂点に向かう複数の辺を持つ可能性がある一方、自身に向かう辺は必ず1つだけある(頂点1を除いて)。制約には書かれていないけどクエリ1において u>v であり、v->a->b->c->d->u という関係があるときに u->v という辺を追加することになる。u から逆辺をたどって v に到達するまでに通る頂点はすべて v に到達可能になり、クエリ2において答えるべき最小の頂点が v になる。辺を順方向に辿るのは行き先が発散して良くないので、クエリ1による変化は行き先が唯ひとつに決まる逆辺を辿って伝える。しかしクエリのたびに逆辺を辿るのでは O(QN) になって TLE が必至。UnionFind のようにグループを管理して、UnionFind の Find 関数のように経路を圧縮したい。■提出 #40061939 (AC / 350 ms)。UnionFind のようにやりました。R=Root, P=Parent, T=Tell, F=Find. ほとんど扱いが同じである R(根)と P(親)を共通化できるかと思ったけど、根へは到達できるのに対して親へはクエリ1が来て T(ell) 関数が呼ばれるまで到達できない違いがあるので分かれている。実は F(ind) 関数はいらないんじゃないかと取り除いてみたりもしたけど、しっかり答えが違ってきてたしかに役に立っているようだった。■D と E と F の精進はまだだよ。詰まってしまった D を後回しにして E にとりかかってそのまま E と心中した結果 A-C の3完だったんだよ。パフォーマンスも新しいレートも知らないよ。G 問題が(事後でも)解けたくらいのごほうびがないとやってられないよ。■なんとなく脳内イメージが 20210902 で解いた ARC056-B「駐車場」に似ている。似ているだけで、共通点があったりヒントにできるかどうかは知らない。たぶん状況の整理が必要な点が似てるんだろう。さっき例にあげた v->u->v という環状構造があるときに、u->b という辺が追加されたらどうか、b->x (ただし x<v) という辺が追加されたらどうか、そして UnionFind がこっそりうまくやるように、すでに環状構造がある2つの連結成分を繋ぐようなクエリ1が来たらどうなるか、を整理する。ああ、だから F(ind) 関数を省くと良くないのはクエリ1の第2引数である飛び先にすでに別の飛び先がある場合があるからだ。それでなくてもクエリ1でショートカットしているからすべての頂点が最終到達点を必ず知っているわけではない(だから F(ind) 関数が必要)。


2023年03月19日 (日) [AtCoder] 今日は ABC294 があった。コンテスト成績証自分のすべての提出。F がほぼ既出の問題(水 diff)だったからなのかは知らないけど、6完でも渋いパフォーマンス。■D 問題「Bank」。この手の、前提知識なしで非効率的ではないデータの持ち方を考えさせる問題好き(賢くて効率的なデータ構造を知識なしで再発明することはもちろんできない)。「Notebook」とか「コンテナの移動」とかも同様。「Simplified Reversi」なんかは工夫した単純なデータの方が BIT を使った場合より log が落とせたりして最高(@chokudai「F問題とても好きな問題なんだけど、データ構造でいくらでも殴れちゃうのが残念……O(N)で解いてみてね><」)。実装しながらもずっと考えていて、検索してみても空振りだったのは、窓口に現れたということをメモする変数の名前。これが一番難しくて頭を使った。適切な名前が付けられたかどうかは知らない。他の人の提出を見て気が付いたけど、数字1つで済ませられるところで自分は配列を2本使う無駄をしてしまっている。■E 問題「2xN Grid」。数字の変わり目を2列で混合してソートして順番に見ていけば一致を数えられる。コンテスト中に不思議なことがあってね、サンプルの3だけ答えが合わないと思って、デバッグプリントを仕込んで数え違いがないかどうか順番に調べていったら手計算と完全に一致していたの。じゃあ自分の問題解釈が間違っているのかと思ってふと見たらサンプルの出力例とプログラムの出力も一致してるの。どこに間違いがあったのか。目か?■F 問題「Sugar Water 2」。「食塩水」とほぼ同じ問題。以前に解いています。「これまで何度も解こうとして解けていなかった問題。(中略) 最終的な濃度を決め打てば各溶液ごとに溶質の過不足が具体的な重さでわかるので……ということでした。」 自分では解けなかったんだね。■G 問題「Distance Queries on a Tree」。やることは難しくない。効率的にどうやるか。HLD の名前を聞いたことはありますよ。コンテスト中は「絶対に初心者でもわかるHL分解/Heavy-Light-Decomposition - Qiita」を読んでお勉強していた。見覚えがあるので以前にも読んだことがあるらしい。具体的な実装方法については知らないまま、同ページによると「かなり重い」らしいですが、雰囲気でまねごとをしてみた。ヌルポみたいなエラーを直せばサンプルが合ったので提出してみたら TLE×18/AC×55 だった。5秒で TLE なのなら頑張るけど 500 秒で TLE なら頑張ってもジャッジに負荷をかけるだけなので考えてしまう。■あ! 部分木のサイズでなく辺の重さで第一子を選んでた! ちょっと待って、修正する。提出 #39886338 (AC / 1797 Byte / 3935 ms)。制限時間ぎりっぎりではあるけど無事 AC でした。■AtCoder Problems に難易度が出たね。F が青 diff 上位なのに対して G が青 diff 下位で逆転している。パフォーマンスが渋いのはこのせいか。G 問題がしっかり崖として聳え立っていれば結果は違った。F 問題について、過去の水 diff が今日の青 diff であるなら、よくいわれる傾向とは逆の結果ということになる。■G 問題。オイラーツアーで解けると何か所かで見たけど解けるイメージがわかなかったので、もうちょっとしつこく考えてみた。オイラーツアーは部分木を一列に連続して並べる方法。辺の重さの変更を部分木にまとめて適用できると何がどうなる? 根からの距離が効率的に更新できる。根からの距離がわかると2頂点間の距離がわかるか? 「頂点 1 からのパスによって決まる値だけを考えて答えを出していい理由は、たぶん LCA までのパスが相殺されるからとか?」からの連想で、LCA を使って引き算すれば求められる気がした。提出 #39906499 (AC / 1407 Byte / 2456 ms)。短く速くなった。しかもバグが .keys 抜けが1つと L[] 抜けが3つだけと実装も素直。根からの距離を BIT で、LCA をダブリングで求めた。根からの距離をセグメント木で管理するなら LCA もセグメント木で求めたらいいと思う。BIT+セグメント木は無駄だし面倒すぎるのでナシ。だってセグメント木は BIT の上位互換でしょ?■提出 #39951562 (TLE×24)。試しにセグメント木で根からの距離の累積和と LCA の両方を管理してみたら派手に TLE だった。累積和は BIT でやる方が軽いのかな。■提出 #39954631 (AC / 3966 ms)。頑張りました。セグメント木にダミーの0番目の要素を入れて添字計算の微調整を省いたり、&:method 形式は Symbol#to_proc が呼ばれるせいなのか知らないけどやや遅いみたいなのでブロックを渡すようにしたり、せっかくセグメント木で累積和を管理しているのだから根からの距離を求めてから LCA を引き算するのでなく LCA からの距離を直接求めたり、オイラーツアーで作成する配列のサイズが 3N くらいになっていたのを節約して 2N に抑えたり。最初の AC だったなんちゃって HLD よりよっぽど厳しい。■モノイドが乗せられるようにまじめに ST クラスを改良したので、クラスを書く時のマイルールを。まずクラス利用者が知りたいであろう public インターフェイスを書いてから部外秘である private メソッドを並べる。public メソッドの中では、最初に呼ばれるであろうコンストラクタ(イニシャライザ)をまず書いて、つぎにアクセサ(読み取りメソッド)を書く。最後に、なくてもいい存在であり有害にもなり得るので書きたくないミューテータ(内部への働きかけ)を書く。クラスはオブジェクトのテンプレートであり、型通りの処理(不変部分)を書く場所だけど、ではオブジェクトのアイデンティティがどこにあるかというとコンストラクタへの引数でありインスタンス変数(メンバ変数)にふるまいを変える固有の値(可変部分)がある。すべてのメソッドがインスタンス変数に依存するべきだというのはそのため。その依存がないならメソッドの置き場所が間違っているサイン。とかとかいうことを考えながらクラスを書いている。あとはまあ名前だよね。よく言われるように名前重要。ソフトウェアという形のないものにはっきりした輪郭を与えるのは名前。適切な名前さえあればその実体をどう実装するかはどうとでもなるしどうでもいい。好きに、うまくやればいい。コーディング対象として適切な抽象に紛れのない輪郭を与える唯一無二の名前を見出すところが決定的に重要(形容詞増し増しで強調しました)。自分が常々疑問なのは、変数名に型名を使うというひとつの典型パターン(var arr = new Array; みたいな)。そりゃね、飼ってる猫が1匹だけならその呼び名はネコでも十分わかりますけどね、それは消去法や文脈でそう判断できるというだけであって、直接的な命名ではない。解釈や判断という余計なステップ、疑問や誤解の入り込む余地がある。クラスではなくインスタンスの、それそのものの本質を掴んだ命名をするのだ。■いやでも適切な命名は文脈に依存するということも言えるんだよな。識別子が機能するためには他と区別するのに十分な長さを必要に応じて使うのでいい。1文字変数を使い切ってから2文字3文字変数を使う、みたいな。ハフマン符号的な。その対極がたぶん Java の説明的で長ったらしい命名で、自分は HTML の p タグとか好きでいっぱい使いたくなる人間だからどちらかといえばアンチ Java なんだな。そのくせ、よそ者として文脈を共有しないで他人が書いたコードを眺めてるときに限って「変数名に型名を使ってる」とかを批判的に見てしまうわけだ。勝手な。