/ 最近 .rdf 追記 設定 本棚

脳log[2023-08-19~]



2023年08月19日 (土) [AtCoder] 今日はキーエンスプログラミングコンテスト2023夏(AtCoder Beginner Contest 315)があった。コンテスト成績表自分のすべての提出。以下 ABCDE のふりかえりと F の精進について。■A 問題「tcdr」。String#tr にはあまり自明ではないふるまいがあって、展開後の第2引数が第1引数より短い場合、第2引数の最後の文字が足りない分だけ補われる。最後の文字が存在しない場合(第2引数が空文字列の場合)は第1引数を削除する処理になる。他の人の提出で今日初めて知ったのだけど、String#delete という、まさに tr の第2引数が空だった場合に相当する処理を行うメソッドが存在していた。それも Ruby-1.8 のときにはもう存在していた。知らなんだ。■B 問題「The Middle Day」。制約が小さいので愚直にやる。だけどあまりに無駄な愚直をやってしまった。"月 日" という文字列の配列を全部生成してから真ん中を選んだんだけど、そこはさ、単に通年での day-of-year を数えておいて、文字列を生成するかわりに適切なタイミングで答えを出力すれば良かったじゃない。■C 問題「Flavors」。フレイバーごとにおいしさを記録してから異種組み合わせと同種組み合わせを考えた。ツイッターを見てると最大のおいしさが必ず採用されることに着目した解法が目立つ。そのアイスを2回食べてしまうミスにだけ注意すれば配列1本で処理できるのが魅力的な解法だと思う。ミスへの対処法は、必ず選ぶ1つを配列の先頭もしくは末尾の要素とスワップして、先頭もしくは末尾を探索範囲から外すのがいいかな。■D 問題「Magical Cookies」。最終的に E 問題の3分の1くらいしか正解者がいないいわくありげな問題。下手をするとすぐ TLE になるみたい? 自分も 35 分と、E 問題より時間をかけて慎重にやっている。TLE 以外に小さな罠もあるにはあって、問題文に書いてある通りの手順を守らないと最後に残るクッキーが違ってくるような気がする。行を取り除くには2列以上、列を取り除くには2行以上残っていないといけないという条件から、残り2行もしくは残り2列付近で手順が最終結果を左右するのではないかと思う。手順を守るように途中で書き直したおかげかは知らないけど、というか書き直しだけなら5回も6回もそれ以上でも行きつ戻りつしていたのだけど、ペナルティを出さずに AC だった。TLE を回避する手段は、まだ残っている行番号と列番号を記録して使用することと、行と列にある文字の種類と数を記録して使用すること。■E 問題「Prerequisites」。スタックに積んで順番に読むだけ。WA を出したのはひとえにあほだからです。もう読んだフラグを立てるタイミングを間違えた。そのタイミングで何かするのを帰りがけ順っていうらしい(聞いたことはあるよ)。■F 問題「Shortcuts」。とりあえず DP で解けるのはわかる。制約が1万以下とよくあるものより1桁少ない。2乗で1億、定数倍2分の1で 5000 万。言語アップデートにより「倍早い」こともある Ruby-3.2 ならワンチャンあるかという数字。時間内に提出したものは TLE だった。ああ無情。■F 問題。悪いのはもちろん Ruby ではない。実は途中で必要に迫られて DP 配列の次元を増やしていた。O(N^3) にはどんなチャンスもない。ツイッターで見ちゃったんですよ、ペナルティは 50 回まで考えれば十分だと。見積もってみれば 28 ビットで上限を突破しそうだったので 30 を上限にしてみたら通った。O(30*30*N) だから 900 万のレベル。大枠は完成していたんだから時間内に通したかったねえ。


2023年08月17日 (木) [AtCoder] 精進1。ABC149-F「Surrounded Nodes」(黄 diff)。前前前回の ABC312-G「Avoid Straight Line」(20230729) を思い出させる問題だった。今日の問題のキーワードは「主客転倒」と「余事象」。ひとつひとつの頂点が穴だと数えられる場合の数を数えて最後にその和を全体で割った。提出 #44647884 (AC / 337 Byte / 588 ms)。■精進2。ABC136-F「Enclosed Points」(黄 diff)。シンプルな問題。これもキーワードは「主客転倒」と「余事象」、それと「包除原理」だろうか。ひとつひとつの点について f の値に寄与する集合 T の数を数えたい。裏返して、寄与しない T の数を数える。それは、T が左(、上、右、下)にある点だけからなる場合。T が左上(、右上、右下、左下)にある点だけからなる場合を重複して数えないようにする。左上にある点の数を数えるのに BIT を使った。提出 #44669970 (AC / 687 Byte / 1095 ms)。


2023年08月16日 (水) [AtCoder] 提出結果ページのソースコードが見られない。「SyntaxError: invalid identity escape in regular expression editor.bundle.min.js:1:882506」というエラーが出るのはブラウザが古すぎるせいかもしれないけど、ページのつくりとして、静的に完成したページを出してからデコレートしてほしい。そしたらデコレート部分がシンタックスエラーで壊れていても影響がない。提出結果ページにおいて不可欠のコンテンツが提出内容であるソースコードだということを忘れてほしくない。そして、コンテンツはマークアップ対象としてあるべきであって、属性値に置くのは筋違いだというのが原理主義的な意見。スクリプトがなくても、スタイルシートがなくても、タグがなくても残るのがコンテンツ。もっとも、最近そういうのは API をたたいて JSON なりなんなりで取得するみたい?■Twitter でも提出結果ページが壊れてるって報告が見えるので流動的だとは思うけど、とりあえずこれで>AtCoder-Submission-Page-Fix.txt。以前の提出結果ページとくらべて copy ボタンは機能しないし行番号もなくなったけど、それでも、最低限はある。ソースコードが読めるようにはなった。


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