/ 最近 .rdf 追記 設定 本棚

脳log[2023-08-15~]



2023年08月15日 (火) [AtCoder] 精進。ABC140-F「Many Slimes」(黄 diff)。問題はシンプルに見える。自身未満の体力のスライムしか生み出せないのだからできるだけ大きい体力のスライムからスタートして、できるだけ大きい体力のスライムを生み出すのが最善。■提出 #44614623 (WA×22)。S をソートして前から 2^k 個の要素が次の 2^k 個の要素より大きいことを k=0..N-1 について確認すればいいかと思ったが違った。多少の融通がきくようだ。■提出 #44621584 (AC / 1076 Byte / 1108 ms)。待ち行列を2本持つことでプライオリティキューを使わないでもいいかなとか考えてダメで、プライオリティキューでやろうとしてダメで、BIT でやった。難しい問題ではなかったはずだが回り道が多かった。■もっと短くてオーダーの優れた賢い解法があるらしい。たぶん最初に最大の要素に N 個の要素を生み出させて、その次の世代に N-1 個の要素を生み出させてとやるのかなと思ったけど、これも単純に前から貪欲にやるわけにはいかないみたい。たとえば最大の要素にはできるだけ大きな要素を生み出してほしいけど、N 番目に生み出された要素が次の世代を生み出すことはないので。


2023年08月14日 (月) [AtCoder] 精進1。昨日あった AGC064(不参加)-A「i i's」。最初は昇って降りる階段を作ればいいのかと思った。1234444332 みたいなのを。WA です。問題をよく読んでほしいんだけど、隣接項の差の絶対値は1か2でなければいけない。ゼロではいけない。せっかくなのでこの階段からスワップを繰り返して答えが作れないかと考えてみたがうまくできなかった。ステップ1。N=5 だとして 545454545 みたいにして5と4のノルマを消費したい。ステップ2。同じようにして 32323 を使って2と3のノルマを消費したいが、54...45 の隣に並べてしまうのは良くない。2個までなら並べられるけど、3回以上並べると第 L 項と第1項の差が4、6、8……と拡大し続けてしまう。5と4のあいだに埋め込むのが正解。1になるまで再帰的に埋め込みます。提出 #44571247 (AC / 461 Byte / 125 ms)。あ、また忘れてた。隣接2項の差がゼロではいけないから、両端が5ではいけないから、1回だけ横に並べたあとで再帰的に埋め込みをします。N が3以上なので必ず1度は横に並べられます。■■■精進2。同じ AGC064-B「Red and Blue Spanning Tree」。初手はひらめきです(初手でひらめいたということではなく、有効な初手をひらめくまであれこれ考えたという意味)。辺を3種類に分類した。すなわち、両端の頂点の色と辺の色が一致している辺、片方だけが一致している辺、両方ともが異なっている辺の3種類。両端が一致している辺はどんどん無条件に使用して良さそうな雰囲気がある。それから。大きさが2以上の連結成分に属する頂点についてはすでに条件を満足している。いまだ孤立している頂点をなんとかしたい。端点の片方だけ色が一致している辺を使ってなんとかしたい。その結果孤立頂点がなくなったなら、あとは使える辺をすべて使って全域木を構成する。もし孤立頂点が残ってしまったなら、答えは No。■WA×33WA×8WA×2WA×21 のち AC。ステップ2で孤立頂点を解消する手順がずっとバグっていた。孤立頂点からすでに充足している大きな連結成分へと優先して辺を引っぱらなければいけなかった。まかり間違っても孤立頂点と孤立頂点を片方だけしか満足させられない辺で結んではいけない。■いやね、その場合でも孤立→孤立→大きな連結成分みたいにして最後に大きな連結成分に行き着くのなら問題がない。でも行き着かないケースもある。それが WA×2 の原因となった cycle と名のつくケースだと思う。手元で作った最小ケースはこんなの 4 4/1 2 R/4 3 B/4 1 B/3 4 R/RRRB。1と2の頂点は1番の辺で両方とも満足している。3番の頂点を満足させられるのは4番の辺だけ。4番の頂点を満足させられるのは2番と3番の辺だけど、2番の辺を使ってしまうと3番の頂点を満足させる方法がなくなってしまう。2番の辺と4番の辺は同じ2頂点を結んでいてそれぞれ異なる側を満足させる対称的な辺だけど、これに正しい優先順位を付けて使用しなければ答えを誤る。


2023年08月12日 (土) [AtCoder] 今日は ABC314 があった。コンテスト成績証自分のすべての提出。配点を見たら 100-200-300-400-475-475-575-625 だったから E と F は易しめなのかなと思っていたら全然そんなことはなかった。E も F も解けず ABCDG の5完。E は解きたかった。ABCDEG ならこれまででベスト3の順位だった。まだ解けないんだから実のない願望ではある。以下 ABCDG のふりかえり。■A 問題「3.14」。切り捨てを四捨五入だと誤読した。小数点以下 N 桁までしか知らされていないのに四捨五入して小数点以下 N 桁を出力するためにどうしようか考えてしまった。0を補おうか? いま再読すると「小数第 N+1 位で切り捨て」と書かれているのがミスリーディングだと思う(やつあたり)。切り捨てであってもないもの(N+1 桁目)を操作することはできないじゃない。考えちゃうよ。提出 #44490051 (AC / 142 Byte / 43 ms)。■B 問題「Roulette」。制約は小さいしやるだけではある。でもあまりやりたくない気分になる。見通しよく素直に実装すると3パスの操作になる。すぱっときれいに片付ける方法はないものか。考えた結果ソートなんてしてしまう人間(私です)は計算量についてイチからやり直そうな。提出 #44494576 (AC / 235 Byte / 44 ms)。■C 問題「Rotate Colored Subsequence」。色ごとに文字を積んでローテートして取り出すだけではある。でもケチなことを考えた。総要素数が N 個になる M 個の配列を作りたくないなと。要素数 M 個の文字配列だけで済ませたいなと。それで TLE を出しているのはただの間抜け。4-7 行目が良くなかった。提出 #44500699 (AC / 220 Byte / 158 ms)。TLE の解消方法がまだいまいち。reverse_each をやめても前から順に常に上書きするなら同じ結果が得られる。■D 問題「LOWER」。クエリ2と3があると文字列の大文字小文字がすべて決まってしまうのだから、文字列を直接書き換える他に、クエリ2と3の後のクエリ1についてだけ記録を残して上書きすればいい。例によって toupper やら tolower やら locase やらを試してとうとうリファレンスを調べた。upcase の反対は downcase らしいです。提出 #44506770 (AC / 266 Byte / 666 ms)。クエリ先読みが有力だったっぽい。■G 問題「Amulets」。問題の構図は比較的理解しやすく、データ構造の知識が問われる問題だった。持ち込むアミュレットの種類は後出しで選ぶ。どのように選ぶか。n 体目のモンスターまでで総ダメージが sa になるとする。モンスターのタイプ別でも総ダメージを記録しておく。タイプ別総ダメージが大きい方から k 個を選んでアミュレットでダメージを無効化するのが最善。その結果総ダメージが H 未満になるならいいが、H 以上になるなら n 体目のモンスターは倒せなかった。アミュレットの個数と倒せるモンスターの数は比例関係にあるので、アミュレットの数とモンスターの数を増やしながら答えを記録していく。たぶんだけどアミュレットは増加していく単一の集合ではないと思う。つまり、k=2 で選ぶアミュレットは k=1 で選ぶアミュレット+1ではないと思う。だから BIT で都度都度最適な k 個を選ぶようにした。top k の総和を効率良く求めることがこの問題の中心だった。BIT にたどり着く前にはプライオリティキューを貼り付けたりしていた(でも行き止まり)。BIT で個数と総和を管理するのはついこの前 ABC312-F Cans and Openers でやったばかり>提出 #44067838。その問題にその解法は log が余分に付くうまくない解答だったのだけど、それが今日の解答のプロトタイプになったのだから怪我の功名。提出 #44529976 (AC / 1412 Byte / 1731 ms)。べつに今回が2回目ってわけでもない。ABC287-G Balance Update Query への提出 #38427641 でもやってる。


2023年08月09日 (水) [AtCoder] 精進1。ABC127-F「Absolute Minima」(黄 diff)。サンプルの1を読めば f(x) を1回2回置き換えたときの答えの求め方がわかる。あとは3回4回のケースが想像できればいい。■提出 #44387658 (AC / 1233 Byte / 858 ms)。f(x) を更新するにあたり b は総和を覚えるだけでいい。a については中央値と中央値からの離れ具合の総和が知りたい。それは a のソート列と累積和があればわかる。おなじみ BIT で効率的に動的に管理する。■■■精進2。ABC130-F「Minimum Bounding Box」(黄 diff)。まず入力を絞る。d={R,L,U,D} それぞれについて X 座標の最大値最小値、Y 座標の最大値最小値にしか用がない。X 座標について考える。X 座標の最大値最小値の差が減るか一定か増えるかが切り替わるかもしれない時刻が4つだけある。右に移動する X 座標の最大値が左に移動する X 座標の最大値と交差するときが1つ。右に移動する X 座標の最大値が上下に移動する点の X 座標の最大値と交差するときが1つ。3つ目と4つ目は同様に左に移動する X 座標の最小値が~。Y 座標も同じく最大4つの時刻で差の増減トレンドが変化する。求めるものは差と差の積の最小値だけど、差の増減トレンドと積との関係はどうなっているだろうか。(差が減る)×(差が減る)=(積が減る)、増×増=増、減×増=?、増×減=?。書いててわからなくなった。差が増減する早さに秒速1と2の2種類ある。1種類なら平方数を最大として上に凸のグラフのある範囲を切り取った変化をすると思ったけど、2種類だとどうなるんだろう。下に凸になることがあると思ったから三分探索をしたけど、今になって三分探索ができる単純な形の変化をするとはわからなくなってしまった。■WA×1 のち AC (1480 Byte / 187 ms)。


2023年08月08日 (火) 悪名高きスワイプ広告を解析する - Qiita」■スワイプ広告というものは知らなかったけど、興味深い分析だった。で、Flash 広告を思い出した。あれはフォーカス(黄色い枠だった?)を得るとすべてのキー入力を呑み込むために Web ページの閲覧を阻害する異物であり嫌っていた。スワイプ広告も埋め込みスクリプトによる治外法権が認められている異物らしかった。再実装されたスワイプ処理がお粗末なのか悪辣なのか外からは何とも言えないけど、治外法権を認めていることがそもそも失策であり現状は予期された帰結だと思う。つくづく癌だよな。■■■思い込みで書いてる部分があった。スクリプトを誰が書いているかという部分。自分は広告の配信者だと思ったが掲載者であるかもしれず、元の記事では「あくまで推測だが、おそらくこの誤タップ広告システムでサービスを提供している会社が存在し、」と第三の存在が推測されている。


2023年08月07日 (月) [AtCoder][Ruby] 「AtCoderの新ジャッジ、Rubyの一部提出がメチャ遅い実行時間になっているのだけど require 'prime' があると遅くなるみたいだなー」 これを見てコードテストで require 'prime' とだけ実行してみたら 2525 ms かかって「マジかー」となったのだけど、その後は 55 ms 程度で落ち着いている。インタープリタ起動のオーバーヘッドがおよそ 40数 ms なので、require 'prime' にかけている時間は 10 ms 程度。まあ妥当。他にも require 'openssl' が数百 ms かかったのも確認したんだけど、次に確認したときは 55 ms になっていた。その次は 80 ms。require ひとつのために確率的に TLE になってペナルティを食らうのは嫌すぎる。■magurofly さんの全く同一ソースの2つの提出がこちら。#44334461 (1897 ms)、#44345492 (66 ms)。一度も呼び出されていないメソッドはコンパイルされないだろうから JIT ではないよね。じゃあ rubygems なのかと思うけど、require 'prime' にネットワークが関わる要素はないよね。ね? じゃあどこで? あるいはジャッジサーバーが?


2023年08月05日 (土) [AtCoder] 今日は第四回日本最強プログラマー学生選手権-予選-(AtCoder Beginner Contest 313)があった。オンサイトコンテストの予選だから問題の難化が予想されたけど、配点でもそれが裏付けられている。100-300-400-550-600-625-625-650 は A-C-D-E-F-Ex-Ex-Ex ってことですかそうですか。今日は 100 分5問の、普段よりビギナー向けのコンテストになりそうですね。以下 ABCE のふりかえりと D の精進。■A 問題「To Be Saikyo」。やることは簡単だけど制約とサンプルがいやらしいですね。ひっかかりません(N=1 のケース)。■B 問題「Who is Saikyo?」。愚直に再帰的に何人に勝っているか数えても許されると思ったけど TLE を出した。「全ての情報が正しくなるように、全ての相異なる 2 人組にどちらが強いかを割り当てる方法が少なくとも 1 通り存在する」という制約から推移律を破るような循環する入力は与えられないと思ったけど勘違いだろうか。あるいは単純に計算量が見積もれていないだけだろうか。N≦50 だから4乗でも通るはずだけど。TLE の原因がわからない。Ruby で最初に提出された #44259309 (kuma_rb さん) の着眼点がすごい。負けなかった人が一人だけいたならその人が最強だと。トーナメントではそういう話を聞いたことがあるけどね(「優勝者とは唯一負けなかった者のことである」)。■C 問題「Approximate Equalization 2」。これは B 問題より簡単だった。平均として考えられる2つの整数(切り捨てと切り上げ)を考えて、A 数列のすべての要素について下げるなら下げる量、上げるなら上げる量を数える。下げる量と上げる量の大きい方が答え。上げるのと下げるののうち操作回数が余った方は2つの平均値のあいだを移動するのに使われている。■D 問題は答えを求める手順がわからなくて飛ばした。もし答えが絶対にわからないときの答え方が用意されていたら、まんまと「わかりません」と答えて WA をもらっていたところだった。■E 問題「Duplicate」。そもそも長さ1に収束するというのがけっこうなレアケース。S="22" でも永遠に短くならない。先頭の文字はどうでもいい。2番目以降の文字が操作後の長さを決める。1なら現状維持(ということは操作により末尾の1文字分減る)。2以上なら伸びる。しかし2から9までの数が2から9までの数を増やして伸びることはない(そうしたら収束しない)。2から9までの数が末尾に至って消滅するまでに何個の1を生成するかを数える問題。右側にある文字数と同じ回数だけ、決まった長さ(1から8)だけ伸びる。右側にある文字数が知りたいので末尾から(ほとんど1の)長さであり操作回数を数える。■D 問題「Odd or Even」。コンテスト終了まで考えていた F 問題 Flip Machines が解けなかったので終了後に D 問題に戻ってきた。N 回のクエリで数列全体の偶奇(の連鎖)が決まるのはわかる。たとえば A[1..K] の偶奇がわかって A[1..K-1,K+1] の偶奇がわかると A[K] を基準にして A[K+1] の偶奇が同じか異なっているか決めることができる。同様にして A[K+2] 以降も決める。A[1] から A[K-1] の偶奇についてもうまいことやって決める。ここからが問題だった。クエリ回数は上限の N 回まで使い切っている。A[K] の偶奇を基準にして同じか異なっているかはすべて判明しているが、A[K] の偶奇を決めることができるのかどうか。たぶんここで K が奇数だということが効いてくるのかな。最初のクエリを思い出そう。A[1..K] の偶奇がわかっている。そして A[K] を基準にした仮の偶奇について、1から K までの範囲の偶奇はどうなっているだろうか。一致しているだろうか異なっているだろうか。もう解けた。■コンテスト成績証自分のすべての提出。D 問題も時間内に解きたかったけど、終了後に1時間かけているので惜しいところはなかった。それというのも人間ジャッジがときどきレスポンスの偶奇を間違えるからなのですね。解答のデバッグと並行していつの間にかジャッジのデバッグをさせられていたのでは時間もかかる。D 抜きでも青パフォが出たのは E 問題様様です。■F 問題について。N≦40 と制約はかなり控えめ。各マシンについてありうる未来はかなり限定されていると思った。操作しなければ2枚のカードについて {表表}。1回の操作で {表裏,裏表}、2回の操作で {表表,裏裏}、3回の操作で {表裏,裏表} これは1回の操作と同じ未来。それでどうする?


2023年08月02日 (水) [AtCoder] 精進。ARC010-C「積み上げパズル」(黄 diff)。色ボーナスもコンボボーナスも全色ボーナスもマイナスになりうるのがゲームのルールとして直感に反する。でも DP をするならそこは問題にならない。DP 配列を埋める初期値にだけ注意したらあとの遷移では比較して大きい方をとるだけ。どういう DP をするか。コンボボーナスを加算するために最後に積んだ色が何色かで M 通りに分類する。全色ボーナスを加算するためにこれまでにどの色を使ったかを 2^M 通りのビットフラグで分類する。M の上限が 10 なので組み合わせた状態数が最大で 10240 通りになる。遷移の回数 N が 5000 以下だからおおよそ 5000 万の処理量は Ruby には厳しいかと思ったけど、テストケースが制約の上限を攻めていないのか処理時間には余裕があった。定数倍2分の1のために必ず立っている1ビットを効率的に省略する方法を考えていたけど必要なかった。■WA×41WA×18WA×3 のち AC。■41→18 で解消したバグは、色ボーナスとして加算する値が落ちてきたブロックではなくすでに積まれている一番上のブロックの色によって決まっていたうっかりミス(21 行目)。■18→3 で解消したバグは、ブロックが1つも積まれていない状態(スコア0)が存在していなかったこと。■3→AC で解消したバグは、それまではちゃんと対策できていたのに他のバグを解消したときに不要になった気がして省略した処理がやっぱり必要だったために生じた新しいバグで、最初のブロックの扱いをどうするかに関わること。色数 M が1より大きいなら特別扱いは必要なくて、他の色の空の状態(スコア0)から遷移してくることでコンボボーナスなしの色ボーナスだけを加算することができる。しかし使われている色が1色だけのときに特別扱いなしでは最初のブロック(コンボボーナスなしの色ボーナスだけ)がうまく扱えていなかった。M+1 色目が追加できたらややこしいことは何もなかったけど、TLE が怖くて1ビットだって削りたかったときにそれは取れない選択肢。


2023年07月29日 (土) [AtCoder] 今日はユニークビジョンプログラミングコンテスト2023 夏 (AtCoder Beginner Contest 312)があった。以下 ABCDF のふりかえりと GE の精進を。■A 問題「Chord」。こういうのはコピペを活用してできるだけミスの混入を避けるべきなんだよね。そういう意味で自分の提出 #44032329 はコピペしたあとに手を動かしていて良くない。Shiro_S さんの提出 #44031960 を見習いたい。■B 問題「TaK Code」。すっかり実装が面倒くさい枠の B 問題。4×4×2=32 マスの黒白を愚直に確かめるだけ。そんなんでも添字の範囲を間違えたりしてたいへんなんですよ。■C 問題「Invisible Hand」。ぼんやりして全然頭がはたらかなかった(いつものことか?)。問題文を読むかぎり必ず答えが見つかるみたいな雰囲気を感じるけど、そうだとはわからない。目に付いた数字で二分探索をするもサンプルの2がありがたくも優しくそれではダメだと教えてくれる。A、B 数列の両端付近の値を候補に加えて二分探索で答えを探したけど WA だった。それならと各数字の前後を候補に加えて 3N+3M 個の数字から答えを探したら AC だったけど、あまりにひどい力業。TLE になっていたらお手上げだった。Ruby で2番目に早く提出された gmmtea さんの決定的な提出 #44046237 がすごい。探索などしていない。■D 問題「Count Bracket Sequences」。2乗が通る制約。(閉じていない)開き括弧の数ごとに場合の数を記録する DP をやってみたら DP 配列を shift したり unshift したりする面白い形の遷移になった。もっと効率的なやり方(※)がありそうではあるけど、制約で許されているので愚直に配列を操作した。※倍の長さの配列を用意して真ん中を暫定の先頭にする。実は Ruby のインタプリタが shift も unshift も勝手にうまくやってくれるので考える必要がない。■E 問題「Tangency of Cuboids」。幾何問題。心中リスクが高いので飛ばした。終了3分後の提出 #44081331 は TLE だった。■F 問題「Cans and Openers」。配点は E 問題と同じ。貪欲法でできるかなと考えてみたけど、缶切りの数に応じて答えがガタガタして無理そうだった。場合分けも、缶切り不要の缶が M 個に足りない場合や、缶切りがあっても缶切りが必要な缶が十分にない場合など、状況と状況の重ね合わせまで考えるとたいへん。2本の累積和からいい感じに M 個を取るという構図から ABC116-D Various Sushi を思い出していた。しかしその精進(20220609)は生きず。BIT を2本使って缶切りの数ごとに愚直に満足度の総和を求めた。Ruby によるすべての提出を見ると、貪欲っぽいもの、プライオリティキューを使うもの、DP らしいものなどいろいろ。log が付くデータ構造を使った自分の提出 #44067838 などは時間が余分にかかっていて、もうちょっと頭を使ってがんばりましょう、という感じ。■G 問題「Avoid Straight Line」。コンテスト終了後に本腰を入れて考えた。単純パスを構成しない3つ組とはどういうものだろうか。制約を見るとペアを考えることが許されていないので、ペアから LCA を求めて……という解法にはならないとわかる。それで、どういう3つ組? 根っこに向かって一直線の3つ組ではない。2頂点とその LCA から成る3つ組(ペアの場合もあるが無視する)ではない。根っこに向かう直線ペアと×××の組み合わせではない。……。部分木ごとに直線ペアの数と分岐するペアの数を記録して根っこに向かう DP をすれば求めたいもの(分岐するトリオの数。変数名 spt は split trio の略らしいです)が計算できそう。提出 #44086692 (AC / 488 Byte / 1741 ms)。サンプルの3が合わないときは3つの子から1つずつ選ぶ spt を数え忘れてるかもね(経験談)。Ruby による G 問題へのすべての提出を見ると自分の遅さが際立っている。なぜ?■コンテスト成績証自分のすべての提出。ABCDF の5完でまずまずの成績。(終了後でも) G 問題が解けて満足している。AtCoder Problems によると難易度勾配は F(水)<G(青)<E(黄) らしいけどね。たしかに、E 問題の TLE を解消する手立てがまだわからない。直方体の数が 10 万あるのに、あれとこれが接触している、これとそれが接触している、と個別にペアを数えてはいけないのかもしれない。だけど6面あって重複をカウントしないように何ができる?■■■G 問題。自分の提出が他と比べて桁違いに遅いのでちょっと考えてみた。前回は子(部分木)ごとにサイズと直線ペアの数を記録して求めるもの(分岐トリオ)を計算して足し合わせていた。分岐トリオを求める計算が余事象が関わっていてちょっと面倒くさい。今日は子(部分木)ごとにサイズと直線ペアと直線トリオを記録して、根っこで一括して余事象を求めるようにした(3つ組の選び方から直線トリオを引く)。提出 #44113272 (AC / 309 Byte / 602 ms)。桁は並んだけど 400 ms 台、500 ms 台に比べると遅い。メモリ消費が4倍くらいあるんだよね。根っこから再帰関数を呼び出すのでなく、葉から根へ積み上げるべきなのかもしれない。だけど記述のシンプルさにはあらがえない。簡潔に書けてると思うん。ゴルフしてるものにくらべるとまだ余計なことをしてる無駄な記述があるみたいだけど。■E 問題。座標空間が 100×100×100 でえらく狭いなと、ここに直に書き込んで何かできないかと考えてはいた。でも 100×100×100×N では TLE だしなーと。見落としていた重要な制約があった!!! 「直方体同士は体積が正の共通部分を持たない」 だったら N 個分書き込んでも総和は 100 万以下じゃん! 隣のマスを見たら隣接直方体がわかるやん! 提出 #44116267 (AC / 553 Byte / 729 ms)。■延長1日を含めてこれもう実質7完でいいんじゃね? やったぜ!(めでたい)■■■G 問題。現在見ている頂点を3つ組の真ん中の頂点だと考えて直線トリオを数える DP ができるらしい(最後に3つ組の全選び方から引く)。提出 #44139844 (AC / 303 Byte / 634 ms)。そうすると直線ペアの数を数える必要がなくなって、サイズと直線トリオの数だけを数えればよくなったけど、期待に反してわずかに遅くなった。400 ms、500 ms 台に入ると思ったのになぜ? 実は答えを合わせるのにすこし苦労して、現在見ている頂点を3つ組の真ん中に決め打つということは、他の2頂点を選んでくるのは子方向の部分木だけに限らず親方向からも選んでこられる(16 行目)。その点がこれまでの2つの解答と異なっていた(これまでは現在見ている頂点が LCA になるような3つ組を考えていたので問題が子孫方向の部分木に閉じていた)。■E 問題。たぶんだけど、サンプルにわかりやすーい図解が付随していたら当日の AC がもっと多かったと思う。問題文を読んでも全然具体的イメージが構築できなくて苦労したもんね。まず直方体の対角線って何だ、とか。それは長方形の対角線とは(必ず)違うと考えていいのか、と。不等号(X1<X2, Y1<Y2, Z1<Z2)に意味を持たせすぎないでもっと文章で説明してくれていいのよ。辺が軸に平行だということも、え、それってどういう、という疑問からなかなか先に進めなかった。脳内直方体は歪んでいた(それは直方体ではなくない? 菱餅? そんなつっこみも出てきやしなかった)。■■■F 問題。自分の提出は BIT を使ったせいで余分な log がついて時間がかかっていた。よく考えて整理した結果、2本の累積和から M 個を取ったあとで綱引きをするようにした。要するに尺取り。提出 #44215202 (AC / 619 Byte / 389 ms)。最速級まではいかないけど BIT 版より倍は早くなった。じっくり整理したので規則的で理解しやすいと思う。S2 に前加工を施すと k1x の補正が必要なくなるし、無意味に缶切りを取得する前に試行を中断できるけど、それは TODO。


2023年07月28日 (金) 初めて免許を取ったときの教習の一幕。S 字を通過していたら止められて、助手席側のドアを開けてみせて見てみろと。こんなにタイヤと縁石が近いと。はあ、なるほど。で、どうすると問われました。(ぎりぎりだけど当たってないので)行けるんなら行きます、と前進しようとしたら呆れられました。いやあ、だって、ねえ、ドアを開けて目視でセーフが確認できたんだから、行きますよねえ。熱烈指導(お説教)が始まりそうな気配だったので慌てて(ルームミラーと後方を確認して)バックして進路を修正しましたけども。前進しかできないわけではないことを証明しましたけども。■何の話かというと、「(ぎりぎりでも、忠告を無視するような形になっても)行けるんなら行きます」という選択をする傾向が他の場面でもあるかもなあと思ったからなのでした。


2023年07月26日 (水) 動悸という言葉について。辞書には「心臓の鼓動が平常より烈しいこと。また、その鼓動」「動悸がする」「動悸を打つ」などと書かれている。つまり動悸という言葉の中にすでに鼓動の早さ強さが含まれている。今日「動悸が早くなった」という用例を本で見かけた。珍しくはない使われ方だけどちょっとひっかかる。「鼓動が早くなった」とか、ちょっと古めかしい定型かもしれないけど「心臓が早鐘を打った」とかで良くない? でも、すでに動悸がある状態がさらに程度を増したというように読み取ることができなくはないかな、と思いもする。そのつもりで書かれただろうとは思わないけど。辞書に書かれているのは前例であり、現在の用例も前例のひとつになりうる。動悸という言葉が使いやすい形と意味を持っていないバグが是正されていく過程にも思える。どっちつかずの微妙なきもちにさせられる言葉。あるいは個人的な見当外れのこだわり。「HTTP プロトコル」の仲間に見えるんだよなあ。Horyuji Temple が仲間に加わるとむしろありの例なんだよなあ。


2023年07月25日 (火) [AtCoder] 精進1。ABC104-D「We Love ABC」(青 diff)。3つの要素があるときに真ん中に注目するという典型をこの前仕入れたのでその方向で考えてみた。各文字を見ていくとき、その文字が B である場合と、? を B にする場合に ABC 数を数えて足し合わせたい。前準備として左にある A の数、? の数、右にある C の数、? の数を知るために累積和を用意する。既存の A のうちのひとつを利用する場合には左にある ? に ABC のどれを割り当てても良い。? のうちのひとつを利用する場合には割り当て可能な ? の数が1つ減る。わかりにくかったのは、文字列の種類数と ABC 数としてカウントするための A の文字の選び方の区別。つまり、? への文字の割り当て方は 3.pow(? の数) 通りあって、それぞれの文字列に対して A の数だけ ABC 数を数えるための重みがあるということ。同一文字列を重複して数えてはいけない気がして ? への文字の割り当て方に制限を加えて順序よく数え上げようとしていたのだけど、全然いらない心配だった。ある A(もしくは A を割り当てた ?)に注目して ABC 数をカウントするときと別の A(もしくは ?)に注目して ABC 数をカウントするときに、それぞれに S 全体が同一の文字列になるものがあってもよい。■提出 #43942246 (AC / 451 Byte / 220 ms)。■■■精進2。ARC092-D「Two Sequences」(黄 diff)。XOR を考えるときに問題を桁ごとに分けるのは基本だけど、足し算がかかわると繰り上がりがやっかいだよね。ひとつの対処法を知っている。ARC158-C「All Pair Digit Sums」を解いていたときのこと。「kotatsugame さんの動画を見ていたら k 桁目を見ているときにその桁の数字と同時に 10**(k-1) で割った余りを持てばいいと教えてもらった。たとえば A={1234,9876} だとして 10^2 の位に注目しているとき、(2,34),(8,76) を処理対象にする。余りの部分は小数点以下の数字みたいなもの。言われたら、たしかにそれでできそうではあるけど、でも、そういう発想はたぶん待っていても出てこなかっただろうな」。そうすると数列をマスクしてソートして、注目しているビットが1になる境界、繰り上がって0に戻る境界、さらに繰り上がってきて1になる境界がこの順で見つかる。時間が厳しいので二分探索を使わずに尺取りでやる。これは2か月に渡って苦しめられた Pairs の教訓。■提出 #43950013 (TLE×4) のち 提出 #43950581 (AC / 515 Byte / 2106 ms)。正直初手で通ってほしかった。TLE を回避した手段はイテレータメソッドを while ループに書き換え、Array#map と Array#sort を破壊的メソッドに置き換えたこと。読みにくくなるだけでアルゴリズム的な改善はない。■Corvvs さんの提出 #3092072 を見ると添字を3つも管理していない。キャリーにだけ注目している。AB 変数の意味もわからない。むむむ。■1のビットの数の増分だけ見てるのかな。キャリーが起こると1が2個減って上の桁で1が1個増える。2個減るのは XOR を考える上で意味を持たないけど、1個増えるのは答えに影響する、みたいな? AB 変数がベースラインで、rmask 変数がキャリーによる変動、とか? rmask 変数の末尾に無条件で 0 の桁を追加してるのもそれっぽい。自分でコードにできるほどはっきりはわかんないけども。■ところで、自分が他人のコードを読むときって、完全に雰囲気で読んでいる。個別の式の意味を解釈するよりも、全体の形(ループとか)に注目している。雰囲気だから「みたいな?」みたいな感想になる。たとえばこのときも「面白いことを書いている人がいる。「ABC303-D この問題の正解者は実は間違っていた」。形式だけ見て気が付いたことを」。どういう値を触っているかだけ見てその値の意味を理解しないまま感想を書いている。細かい話は苦手なんだよ。確率・期待値・数え上げ問題の数合わせとかもー最悪。■提出 #43953782 (AC / 484 Byte / 1605 ms)。キャリーによる増分に注目するので間違いなかった。でも伏兵があった。ベースラインとなる繰り上がりを考慮しない和(それは XOR と等しい)の XOR を求めるところに罠があった。項数 N が偶数の時はきれいに打ち消し合って0になるのだね。これはきっちり式を整理して計算しないと気付けない。■提出 #43989881 (AC / 842 Byte / 1496 ms)。Array#sort(一般に NlogN)の隣で二分探索を尺取りにしてもそれは定数倍の改善だし、3つの尺取りが1つの尺取りになってもやっぱり定数倍の改善だけど、ソートを工夫するところまでやると log が落ちて Nlog(N)log(max A) が Nlog(max A) になるっぽい。「数列のソートに桁ごとのバケットソートを使用します。下位の桁から順に計算していけば基数ソートの動きそのままになるので、各桁で O(N) でソートが可能です」 ちょっとだけ早くなった。ちなみに、配列の確保&使い捨て(15-16 行目)を抑制しようとして添字をちまちま操作しても Ruby の場合は逆に遅くなったりする。実際にローカルでは遅くなった。


2023年07月23日 (日) [AtCoder] 精進。ABC142-F「Pure」(青 diff)。すんごく難しかった、というか、ややこしかった。これってうまい書き方があるんだろうか。「すべての頂点の入次数が 1、出次数が 1 であるような G の誘導部分グラフ」というのは要するに輪っかのことで、しかも輪っかを横切るショートカット辺が存在しないもののこと。N の2乗が通る制約ではあるけども、すべての頂点を始点にして輪っかを検出して、輪っかのパスを辿ってショートカット辺が存在しないことを確かめて許されるのかどうか。■提出 #43905266 (AC / 967 Byte / 77 ms)。再帰関数のパラメータとしてパスを表す配列と、再訪確認のためにパスをメンバとするハッシュ表と、調べたけどダメだったことをメモするハッシュ表を渡している。もっとうまいやりようがありそうなものだ。■輪っかの検出ロジックは、終点を決めて、終点の隣接頂点の1つを始点にして終点への到達可否を調べる。そのときに始点や中継点において、終点に到達したパスの中に2つ以上の隣接頂点(←始点や中継点にとっての)が含まれていないことを確認している。2つ以上の隣接頂点が関わる輪っかはショートカット辺がある輪っかなので。これを愚直に繰り返すと TLE になったので、ダメだった結果をメモしている。輪っかにならなかったケースとショートカット辺があったケース。メモの利用は中途半端で、輪っかの終点を切り替えるごとにリセットしてしまっている。輪っかなんだから(輪っかを検出するための便宜上の)終点をどこに取ったとしてもショートカット辺があるせいでダメだったという結果は共有できるはずなんだけどしていない。あと必要だったのは終点を含まないところで輪っかができてしまうケースの除外。それはいま関心がある部分ではないので後の処理を待ってほしい。再帰関数で同一頂点への再入を検知してリターンしないとスタックを使い尽くしてしまった。■これって強連結成分を定型的に列挙してショートカット辺をちょちょいと調べて終わりだったりしたのでは? 自分は何か輪っかの検出で苦労して、輪っかの検出とショートカット辺の確認を同時にやろうとしてさらに苦しくなっている雰囲気。DFS 2回の SCC 分解がそらで書けるほど身についてないから仕方ないんだけど。■日記を書くために自分の解法を書いていたらこれがなんで AC なのかわからなくなってきた。それでひとつの発見があった。最初に「要するに輪っかのことで、しかも輪っかを横切るショートカット辺が存在しないもののこと」と書いたけど、ショートカット辺はただのショートカット辺ではなくて長さ1のショートカット辺だった。誘導部分グラフに含まれる辺と含まれない辺を考えれば当然のことだけど。そうするとひとつの疑問がわいて、どんなループでも、許されない長さ1のショートカット辺を本式の、ループを構成する辺として採用することで答えにすることができるのかどうか。できそうな気がする。それで実装が簡単になるかと思って別解を書き始めたけど、べつにそんなことはなかった。■提出 #43935918 (AC / 1048 Byte / 69 ms)。長くはなったけどややこしさは減って、シンプルに閉路検出&コンパクト化で答えが得られるようになった。■この問題を選んだきっかけはこの前の ABC311-C「Find it!」で閉路検出を書いたからで(#43848448)、その目論見が外れてやけにややこしい解法に当初はなったけど、別解ができてみると狙いが外れていなかったことがわかる。グラフの形がちょっと複雑になって、閉路のコンパクト化という処理を追加したものがこの Pure という問題だった。