/ 最近 .rdf 追記 設定 本棚

脳log[2024-02]



2024年02月03日 (土) [AtCoder] 今日は日本レジストリサービス(JPRS)プログラミングコンテスト2024(AtCoder Beginner Contest 339)があった。D 問題で無駄に定数倍に苦しんだり、F 問題で多倍長整数によるチートが可能だったりと、Ruby で参加している自分と C++ で参加している人とでは見えている問題が違っているコンテストだった。惜しむらくは F 問題の愚直解法を完成させることさえ時間内には間に合わなくて、損するばかりで得をし損ねたこと。結果は ABCED の5完。ではふりかえり。■A 問題「TLD」。ドットジェイピーを切り出す。split してもいいし、拡張子を取り出してもいい。ライブラリにあるでしょう。■B 問題「Langton's Takahashi」。シミュレートする。添字をループし忘れて1ペナ。■C 問題「Perfect Bus」。累積和の最小値をゼロに合わせたときの累積和の末尾の値。■D 問題「Synchronized Players」。二人の位置をキーにして BFS。……なんだけど、TLE を2回出した。しょうもな。しょうもないのは、コピペによる定数倍の改善。そんなことしたくない。■E 問題「Smooth Subsequence」。1点更新のセグメント木。やりたい操作を考えて、それができるデータ構造を知っていれば、やるだけ。■F 問題「Product Equality」。値が十進1001桁になりうる以外は普通の2乗の DP。案外 Ruby だとそのままいけるんじゃね?と思って愚直解を書き始めたんだけど、時間内には完成しなかった。1の要素を特別扱いすると答えが合い、提出したら TLE にもならなかった。D で無駄に苦しんだ分、F でずるして得したかったけど、取り返せなかった。残念。


2024年02月10日 (土) [AtCoder] 今日は鹿島建設プログラミングコンテスト2024(AtCoder Beginner Contest 340)があった。では ABCDE のふりかえりと G の精進を。■A 問題「Arithmetic Progression」。やるだけなんだけど、step メソッドでうまくやりたかったね。ループを回してしまった。■B 問題「Append」。配列が扱えますかという問題。■C 問題「Divide and Divide」。C 問題らしからぬ制約にびびるけども、対数時間で底にたどりつく。1ステップ当たり2分岐あるのが不安だけど、メモ化再帰でダメなら泣いちゃう。Ruby で最短の提出 #50173926 はループなしの計算で解いている。式の中にビット長が2回出てきているのが目を引くが、意味はわかりません。■D 問題「Super Takahashi Bros.」。最初はステージ1から N-1 まで順番に処理する DP だと思った。しかしワープ土管は先へ進むだけでなく前に戻るパターンもある。D 問題でひっぱり出したくはなかったけど頭を使いたくもなかったのでプライオリティキューを貼り付けた。■E 問題「Mancala 2」。最初は前々回の D 問題 Island Tour のように、変化量をため込んでおいて最後に累積和を答えにするのかと思った。そうではない。操作のたびに箱にあるボールを数えて空っぽにしなければいけない。では愚直に操作しよう。BIT で効率良く処理しよう。自分にはめずらしくコメントが書いてある>#50168931。そうしないとややこしくて間違えると思った。1ループ当たり BIT の操作が最大8回あり、入力と出力のそれぞれで N 回の操作がある。N と M の最大が 20 万のときに、(2N+8M)logN のステップは Ruby では非常に不安。わかりやすさのために処理を刻んだけど、TLE になったらいくつかの BIT 操作をまとめるせこくて間違いやすい節約術が求められていた。幸いにも出してみたら 572 ms で余裕のセーフ。■G 問題「Leaf Color」。まず頂点数1の誘導部分グラフは必ず OK。頂点数2のパスグラフも同色の2頂点を組み合わせて問題なく作れる。3頂点から様子が異なる。2頂点を結ぶパスに3頂点目が含まれている場合、この誘導部分グラフは2頂点の組み合わせとしてもう数えてしまっている。余りの数で答えなさいという出題形式から予想できることだけど、頂点同士の個別の組み合わせ、個別のパスをひとつひとつ考慮して数を数えることは許されない。どういう特徴量によれば計算で数が数えられるのか。ある部分木について、色ごとに端点の選び方の通り数を記録した。あとは DP。ある頂点を根とする部分木について、子と子の組み合わせを数え、根と子の組み合わせを数える。提出 #50189012 (AC / 591 Byte / 1023 ms)。木 DP はコードが長くなりがちだけど、9割方は定型の処理であって、この問題に固有の部分は 20 行目と 25 行目ぐらいのもの。その式が見えるまでは何度も何度も合わないサンプルに苦しむんだけど。やっと見えても最初は TLE (#50187841) だったりした。マージテクが使えるように数える数を工夫して、別口で行っていた集計もすでにある数を流用するようにしたら AC だった。こういう解ける G 問題を得点にしたいなあ。正直、木の問題はボーナス問題だと思っている。自分のレート帯を基準にしてだけど、知っているべきことは全て知っているし、解けない問題はないと思っている。こういう強気の姿勢大事。気持ちが負けていると解けない理由を探してしまって解けるものも解けなくなる。そしてあえて水をさすことを書くと、気持ちだけでは解けない問題は解けないのもまた事実。■F 問題「S = 1」はさっぱりです。これが水 diff ってまじなのですか。青じゃないということは、目の付けどころ次第であっさり解けるタイプの問題なのかな。あっさりとさっぱりは似ているけど通じていないよね。私はさっぱりの方でした。三角形の面積の公式を検索して |XB-AY| = 2 の式までは出ていた。しかし探索ができる制約ではなく、そこから何も手が出なかった。高校数学の演習課題でよくあったパターン。手段は授業で教わっているので、ヒントをもらえば最後まで書ける。だけど最初のとっかかりが何もなくて途方に暮れる。それはつまり、知識はあれども理解するには至っていないということなんだろう。そういうようなことが『技術の創造と設計』(畑村 洋太郎) などに書いてある。


2024年02月15日 (木) 「Windows 11 バージョン 24H2」はPOPCNT命令を備えたCPUが必須? 化石レベルでは起動せず - やじうまの杜 - 窓の杜」■今使ってるのは PhenomⅡ X3 だから 2010 年より前だけど SSE4a には対応してるみたいなので大丈夫だな。化石じゃないってお墨付きをもらっちゃった。


2024年02月17日 (土) [AtCoder] 今日はトヨタ自動車プログラミングコンテスト2024#2(ABC341)があった。C 問題難しすぎ。では ABDEF のふりかえりを。■A 問題「Print 341」。問題文が意図的に不親切だけど、曖昧ではないので、指示された通りに出力する。■B 問題「Foreign Exchange」。0 から N-1 まで順番に処理する DP。■C 問題「Takahashi Gets Lost」。500 の3乗を計算してみて不穏な気配はあった。制限時間が長めの3秒だけど足りない。しかし Ruby で通すのが不可能というわけではないらしく、1秒、2秒、3秒程度で通している3つの提出がある。だったらしかたないね。想定解が愚直シミュレーションだとしても、それがだめなときに選ぶプランBを持っていないのが悪い。F を通したあとに 15 分残っていたら慣れない C++ で書き直したけども。Crystal を使わないのはね、処理系がインストールできないからなんだよね。Windows Vista にどうやったらインストールできるんだろう。Rust もできなかった。■D 問題「Only one of two」。二分探索。最初なぜか二分探索を2段階に分けて実行しようとしていたんだけど、2段階目を書いているときにそれがそのまま1ステップで答えを出せることに気がついた。無駄に時間を使ったね。■E 問題「Alternating String」。反転する区間の内部では操作1の前後で状態は変わらない。BIT などで境界部分の状態を記録すると、ある範囲の境界状態の累積が対数時間で取得できる。添字でバグらせてペナルティ 10 分。■F 問題「Breakdown」。残り 10 分ぐらいで一応の解答が完成したんだけど答えが合わない。条件の2つめ「x に隣接するいくつかの頂点からなる(空でも良い)集合 S であって、∑y∈S​Wy​<Wx​ であるものを選び、S に含まれる頂点それぞれに 1 個ずつコマを置く」のシグマを見落としていて、Wy<Wx なるすべての y∈S にコマを配置できるものだと思っていた。残り 10 分でこの思い違いは厳しいが、幸いにもある頂点を選ぶ選ばないの愚直2乗 DP が許されていたので間に合った。うれしい。何番目まででいくつ選んだときの最大がいくつという DP が求められていたら無理だった。解法は、W が小さい頂点から順番に答えを計上する。それは配置されているコマ数×倍率。倍率を決めるために W が小さい頂点から順番に DP をしているし、ある頂点の倍率を決めるためにも W 未満の範囲でまた DP をしている。■自分のすべての提出。C 問題が解けていないことを除けば上出来。コンテスト成績証。1400 に復帰しました。1500 にもう一度のせて青を窺いたいところ。■C 問題。提出 #50395575 (C++ / AC / 637 Byte / 93 ms)。提出 #50396690 (Ruby / AC / 259 Byte / 66 ms)。Ruby が速すぎる! コンテスト中にこれが通せないのはお前が抜けてるからだってはっきりわかんだね。■C 問題。Ruby で最初の AC であるこちらの提出 #50356929 を見ると、18 行目の uniq! がポイントかなと思った。自分の TLE 提出である #50356164 が3行目でやってる文字列置換も目的は同じだけど、やり方が拙くて不十分。自分は経路の冗長性を取り除こうとしているが、経路をたどった結果の到着点の重複を取り除くことで冗長性を除くべきだった。だけどそのときは方法が思いつかなかったんだよ。理由もわかる。重複を取り除くためにはいったん配列などに溜めて並べて比較する必要がある。だけど自分の解答の構成はループを回して逐次的に移動先を更新していた。同時には1つの到着点しか存在していないのだから、それらを比較して重複を取り除くという発想が自然には出てこない。全体を俯瞰して最適な構成を考えることができなかったのは、問題の理解が浅かったからにほかならない。残念だね。


2024年02月25日 (日) [AtCoder] 昨日は HUAWEI Programming Contest 2024(AtCoder Beginner Contest 342)があった。結果は知らない。ABCD のふりかえりと EF の精進を書くよ。■A 問題「Yay!」。人間はひと目で見つけて数えて答えが出せるけど、コンピュータにやらせるのが同じ程度に簡単なわけではない。Ruby には便利メソッドがあるので Array#tally だとか Hash#invert を使って見た目だけは簡潔にできるけども、さもなければ手間を惜しまず堅実にステップを刻むのがいいと思う。■B 問題「Which is ahead?」。人から位置への逆引きインデックスを作っておく。A 問題より簡単では?■C 問題「Many Replacement」。昨日の不調はここから始まっていた。前から順番に置換表を更新していってもサンプルが合わない。それは、連鎖的な変換が考慮されていないから。連鎖的、再帰的ということで UnionFind で解けるだろうとは思ったけど、どうにも無駄に牛刀を持ち出しているように思える。結局置換表を逆順に更新していくことで答えが出せたけど、12 分かかってるんだよなあ。他所で読むまで気付いてなかったんだけど、想定解は置換表(サイズ26)を毎回スキャンして置換する 26×Q≦520万ステップの愚直解法だったんだろうか。そうか、フルスキャンをしても 26 か。■D 問題「Square Pair」。いかにも D 問題らしく、シンプルに効率を求められる問題。苦手な部類。平方数を列挙しようと思ったけど、上限が A.max**2 になるのでためらってしまった。A.max は 20 万。そのループの中で A の各要素について対になって平方数を作るものの存在を確かめるとなると、A.max×N≦20万×20万 になる。次は素数を列挙しようと思った。A の素因数になり得る素数は2万個以下。A を素因数分解して奇数個の素因数の積として分類し直すと、掛けて平方数を作る組み合わせは同じグループからの組み合わせに限られる。このように答えの出し方はわかっているが、果たして2万×N で間に合うだろうか。比較的遅いことはわかってるけどとりあえず Integer#prime_division を使った解答を提出してみて、それで間に合っていた。約1秒。他の人の提出を見ていたら require 'faster_prime' しているものを見つけた。なにそれ知らない。■E 問題「Last Train」。これは精進。パラメータが多くて頭が壊れてしまった。解法はすんなり出てくる。ゴールの N に到着する最も遅い電車を始点にしてプライオリティキューでダイクストラ法をする。しかしパラメータが多いのと、最短ではなく最遅を求めるというので、普段と勝手が違って無限にバグを生み出し続けて時間切れになってしまった。キューに入れるのは時刻と街のペア。たくさんあるパラメータはキューに入れる次の時刻を計算するために使う。あとはがんばって頭の中を整理すれば答えは合う。だけど昨日は、列車の運行を逆向きにたどっていることが合わさって、出発時刻と到着時刻の前後関係がどうあるべきなのかとか、判断をするその時刻に k 項ある等差数列の先頭末尾どちらの数字を使うのかとか、およそすべてのポイントで間違えた。■F 問題「Black Jack」。これも精進。昨日も今日も WA を出したがやっと AC が出た。まず、ディーラーの値 y が L≦y の範囲でどういう確率で分布しているかを知るために 0 から N まで DP をする。E 問題もそうだったけど、この問題も考えることが多くてこんがらかる。y<L の範囲ではサイコロを振るけど、L≦y の範囲では振らない。今 DP で求めようとしているある場所にいる確率というのは、同時に、サイコロを振って次の場所にいる確率を求めるために使う値にもなるのだけど、L を境界として両者が異なる値を取るということ。そこをきっちり区別しなければいけない。ところで、サイコロは D 面あり、DP のためには D 個の値の合計が知りたくなるが、愚直に合計するには D の数が大きすぎることがある。こういうことを1つのループの中で全部考えながら整理するのは非常につらい。今回も evall のとき(20240128)と同じように class を使った別解(#50640033)を書いた。解答の後半は前半とは逆に N から 0 に戻る逆順の DP をした。N にいるときがスタート。サイコロを振れば必ず負け、サイコロを振らないときは y=N の場合を除いて勝つ。y=N の場合の確率は前半の DP ですでに求めている。後半の DP でもサイコロを振った場合の勝率を求めるために D 個の値の合計が必要になるので、前半と同じ class を使って楽ができる。そのクラス(LastNSum)を読み直していたら、@first が完全に無意味なことに気がついてしまった。pop 操作があるなら意味があっただろうけど、ないのでいらない。■自分のすべての提出。レート遷移は知らない。どれだけ減ったかなんて知りたくない。