9.....
だけ見て「はいはいいつものね」と油断した対応をしているけど、初心を忘れていなかった頃は、irb を開始して require'prime'
して 998244353.prime? #=> true
を確認していた。この数字をまともに読んだことも入力したことも一度もない。ずっとコピペしてる。覚えゲーは成立しないのです。だから素数って書いてあると嬉しい。*
を補って全体を N 行 M 列に揃える。次に配列を transpose して reverse する。この時点でほぼ出力ができあがってるんだけど、各行末尾の *
を取り除いてから出力する。■C 問題「Balls and Bag Query」。Hash で個数を管理してサイズを答える。カウント 0 になった要素は取り除く。■D 問題「Cuboid Sum Query」。3次元の累積和。具体的にイメージができないので、機械的に操作をする。うまく1次元の操作を2次元3次元に拡張できるといいね。行列計算がそうだしこの問題もそうだったけど、自分は必ず演算対象の次元数を勘違いしてエラーを出す。数値に対して配列のメソッドを呼んだりする。包除も機械的にやる。3つの次元について L を使うか R を使うかの2通りがあるので全体では 2^3=8 通りの累積和を足し引きする必要があるが、3つとも R を選ぶのが全体であり、そこから引いたり引きすぎたものを足したりするのだから、3個の R を選んだ場合をまずプラスにして、つまり奇数個の R がプラスで偶数個の R がマイナスになる。これはコンテスト終了後に AC が出たからわかったようなことを書いている。コンテスト中は飛ばして E をやっていた。D と E がどちらもたいへんなら配点の高い方に時間を使う。■E 問題「Manhattan Multifocal Ellipse」。D (入力値) の最大値が 100 万だということで、平面上のエリアを具体的に特定できると思った。X 座標と Y 座標を分けて考えるけど、それぞれプラスマイナス D の範囲に限ることができる。D×D は通らないけど、1つの軸を1つずつ走査しながらもうひとつの軸が効率的に数えられたらいい。(WA×1/TLE×5/AC×23) までは行ったんだけど、log の2乗は「効率的」ではないんだよなあ。でも尺取りをするのもたいへん。(WA×1/TLE×11/AC×17) の構造を崩して改善した結果がさっきの TLE×5 なのであって、さらにぐちゃぐちゃ書き直したくない。それが済んでも WA×1 が残る。■F 問題「Maximum Composition」。制約が小さい。K は 10 以下だし、(A,B) の組み合わせも 2500 通りしかない。ということは最大 20 万個の (A,B) には重複がたくさんあるのだが、K 個以上は K 個と変わらない。という感じでなんとなく状態数が少ないような気がしたからといって、メモ化再帰をするだけでは TLE になるのだなあ。コンテスト終了後に取り組んだけど TLE だった。■なんと ABC の3完だ。自分のすべての提出。いまもって E も F も AC が出ないのだから、D の AC が時間内か終了後かはどうでもいいよ。どっちでもだめだよ。■E 問題。AC 出たよ。提出 #56580497 (AC / 942 Byte / 642 ms)。一方の軸を走査しながらもう一方の軸について数えるのではない。それぞれの軸について独立に、座標を、距離の総和に変換する。あとは距離の列と列をソートして尺取りっぽく和が D 以下になる組み合わせを数える。そうしたら TLE が解消しただけでなくなぜか WA も消えていた。コードはほぼすべて先の2つの提出のコピペであって、なんの修正もしてないのに、謎だ。これで A から E まで AC が出たけど、100 分で5完の目がある問題セットではなかったな、というのが感想。D も E も実装が重い。かといって4完ではなく3完なのは全くの想定外。これまで2回くらい脳みそにクモの巣が張ってるって日記に書いてるけど、それってブレインフォグっていうんじゃあありませんか?(何かのせいにしたいだけ。キミはもともとそんなのだ)■F 問題。どうするのかなあ。引数が大きくなればなるほど A が作用する比重が B のより大きくなっていくのを利用して状態数を減らしたい気がするんだけど、A 対 B の2次元の表に線を引いてトップ K を選ぶことってできない。■D 問題の提出一覧を見てると、自分のが特に遅い。3秒制限ぎりぎりだから当然なんだけど、どこが遅いのか。3次元累積和の作り方が下手っぽい。自分のは余分にループが回っている。なにか標準的な手順があるのだろうか。自分はまず3次元空間を用意して、3つの軸について順番に一方向に寄せるように累積和を作成していった。無駄があるのは、3つのパスで順番に、1次元累積和の作成、2次元累積和の作成(1次元累積和のマージ)、3次元累積和の作成(2次元累積和のマージ)を行っていて、たぶん3つともに3乗の時間と空間が使われているところだと思う。どうもね、すでに更新済みの累積和を参照しながら1パスで3次元累積和を構築してる提出が多いみたい。それってややこしすぎません?sweet\nsweet
を検索していたのを修正して sweet\nsweet\ns
を検索するようにした。■B 問題「Grid Walk」。やります。B 問題にしては実装が重め。グリッドのサイズが小さくても実装量が減るわけではないんだよね、当たり前だけど。そこんとこ承知してくれているかな?■C 問題「Minimum Glutton」。C 問題で DP か? と一瞬身構えたけど、最小値を求めるということで、2通りの貪欲法を比較するだけ。大丈夫です、最大値を求める DP 問題は E にあります。■D 問題「K-th Nearest」。二分探索してくださいという問題にしか見えなくて他に方法が思いつかないんだけど、制限時間3秒のところ、(1割増しの 3.3 秒ではなく) 3.22 秒かかって TLE だったので、220 ms ほどの高速化が必要。どうするの?■E 問題「Maximum Glutton」。C 問題の難しい版。甘さとしょっぱさの組み合わせを状態のキーにはできないけど、甘さとしょっぱさのどちらかと個数を組み合わせてキーにすることはできる。甘さをキーの1つにしたら、しょっぱさを最小化する DP をする。これもサンプルが教えてくれたんだけど、A 問題と同じ罠があります。同じ罠に落ちかけました。■F 問題「Range Connect MST」。どういう風に辺を引くことになるのか、イメージがしづらい。木なので本数は N+Q-1 本だと決まっている。それを最大 N×Q の組み合わせからどう選ぶと全域木になるのか。あれこれ考えてようやく納得できたのは、i=1..Q において、Li..Ri のあいだに連結成分が g 個あるなら、g 本の辺を引くのだということ。両手の 5+5 本の指を使って考えると、それで N+Q-1 本の辺が選ばれるようだったのでそう思った。答えが合わなくて時間内に提出できなかったんだけど、原因がしょうもなくて、貼り付けた BIT のイニシャライザにある初期化コードが今回は不要だと思って削除したけど、削除してはいけなかったという、そういう理由で答えが合わなかった。たとえばヒープだと、ソート済みの配列を内部データにする場合、初期化の必要がない。ソート列はそのままでヒープの要件を満たしている。だけど BIT の内部データは違うんだなあ。解ける問題だったなあ。1から数年前の自分なら解いていたなあ。■自分のすべての提出。最近ユーザー名の横に表示されるへの字。ノイズではあるんだけど、水色でもまだ 1500 台を維持しているなという慰めにもなっているもよう。■精進。D 問題。Q のループの中で二分探索をする中で二分探索を2回行って TLE を出していた。二分探索の上限を指定せずに TLE×11。上限を指定して TLE×7。最も内側にある2個目の二分探索を省けるときは省くようにして TLE×1。最内の2個目の二分探索を完全に省いて AC。これが 1765 ms なんだけど、Ruby で 627 ms で解いている人がいるんだよね。気になるけどネタバレは嫌だ。■D 問題。別解。提出 #56088391 (AC / 325 Byte / 340 ms)。log 1つでできると読んだので、k 幅のウィンドウを二分探索で置いてみた。判定条件は、右端の要素が初めて左端の要素よりも b から遠くなる瞬間。そのひとつ手前では逆に、左端の要素が右端の要素より b から遠くなっている。この両者を比較する。二分探索の高速化っていうと尺取りが定番なんだけど、だから昨日はその方面で TLE 回避策を考えたりしてたんだけど、この D 問題はウィンドウの幅 k がクエリごとに可変だから、尺取りはうまくない。今日の提出では同じ二分探索を使っていてあまり違いを感じないんだけど、よく見れば二重の log が一重に減っている。log 1つの差ってたしかにこれくらい微妙なものではあった。Pairs を解いていたときに書いている。「log ひとつの差ってちょっとした違いなんですよ。ちょっと見る角度を変えるだけ」。提出したあとでもういちどさっき読んだブログを読み返すと、まんま自分の提出がやっていることが書いてある。「初めて左端のが遠くなった場所を見つけてその一つ前も(存在すれば)候補なので比較して」。なんかよくわからんなあと思いながら読んでいたけど、実際今も「自分より1離れたもの同士を比較」「長さが1短い区間を考えて」「初めて右のが遠くなったら左のを付け加えてそれがそのまま答え」とかよくわからないんだけど、必要なことは一度読んだだけで頭の中に入ってるんだな! 自分では思い出せないだけで。しじゅうく‐にち【四十九日】〘名〙 人の死後四九日目に当たる日。また、その日に行う法要。」とか書いてあって、これもうわかんねえな。いやホントはわかりますよ。「四十九日」「七七日」の2つと「四九日(目)」とでは使用時期にずれがある。辞典の言葉は収録される言葉よりも新しい。23 日を二三日と書くことの帰結として、10 月が一〇月になっていたのが先々週読んでいた小説。何を今更感しかないけども、そうなんだ、そりゃそうなるよな、だけど気持ち悪いな、その○はなんなんだ、漢字ではないよな、とひっかかってしまったのが今日の日記になっている。十月って書きたいよ。■ATOK で 10 を変換して出した一〇で使われているのは○ではなかった。U+3007 は「漢数字ゼロ IDEOGRAPHIC NUMBER ZERO」であり、U+25CB 「丸印,白丸 WHITE CIRCLE」とは異なる文字だった。〇が比較すると新しい字だけど数百年はさかのぼれるみたいなことが Wikipedia の漢数字のページに書いてある。お前漢数字なのか。漢数字とアラビア数字を区別して一方では位取り記数法を認めたくないっていうのは、単に好みや慣れや、旧弊に囚われているってだけなのか。自分はこれからも区別して用途を分けていきます。■用途を分ける(漢数字では位取り記数法を使わない)ことの別の一面は、「健康第1」とか「3位1体」とか「別の1面」とは書かないということ。算用数字を使うのは1、2、3と数を数える場面だけでいい。X と X+1 が可換な場合だけでいい。七七日 。
A-M$N-Z
と並べたなら、(A,N),(B,O),(C,P),...,(M,Z)
のペアを作る(のだと思う)。ローカリティに注目すればなんとなくそれでいいような気がするし、逆に両端からペアを作っていくのがダメなのもわかる気がするが、いつでも絶対それで OK とはわからない。■自分の解答の後半のステップはプライオリティキューを使わないで、単純に入れ子配列をフラットにして真ん中で切ってペアを作るので良さそう(C.flatten!; C[C.size/2..].zip(C)
)。どの解説もそういうペアの作り方をしてるので。どの頂点集合も過半数に届かないようにしているのだから、たしかにそれで同一集合からペアを作ることはないみたい。それと、DFS での頂点の並べ方は帰りがけ順でも OK と解説に書いてあった。