W
と M
。W 関数は表現したい区間の幅に対して、組み合わせるべき区間の幅を返す。連想配列 M は W 関数によって正規化された区間幅 w に対して、区間 [1,w] が何番目に提示した区間であるかが記録してある。■D 問題「Make Bipartite 2」と E 問題「Choose Two and Eat One」の精進はまだだよ。解けてないんだからしかたないね。残念なことがあったんだよ。■C 問題「String Delimiter」はいろんな解法が考えられて他の人の提出を見るのが楽しいかもね。でも現実問題として CSV を処理しようとするとどんな実装をした場合でも完璧には処理できない狂った仕様の CSV の実在が確認されそうで怖い。提出 #37330344 (AC / 83 Byte / 155 ms)。引用符で分割して奇数番目と偶数番目で処理を分ける、たぶんオーソドックスな方法。入力と出力で文字列長が変わらないことを考えると富豪的ではあるかも。スクリプトだから気軽に split とかやっちゃったけど。■D 問題。こちらのツイート「D dfsで各連結部分の色を塗りわける。色が塗り分けられないときは0。そうでない場合、ある連結成分については「異なる色の個数の積 - 辺の個数」、異なる連結成分通しは無条件で塗ってOK。辺を重複して数えないように注意。」を読む限り考察は完了していたと思う。提出 #37345235 (WA×20)。デバッグするだけだと思ったから E 問題へ行って、帰って来られなかったんだよね。それはそれでしかたがない。E 問題の、ああいう形の繋がり方から全域木が見えなかったことこそ問題。全域木が見えたら持つべきデータの形に頭を悩ませることもなかった。■D 問題。お風呂デバッグ完了しました! U(nite)関数において引数の2頂点のあいだに辺を張るべきところ、その根と根のあいだを辺で結んでしまっていた(と思う)。提出 #37379282 (AC / 604 Byte / 438 ms)。前々回の ABC280-F が重み付き UnionFind だったんだけど(20221203)、付随データが数値(距離)から二値(偶奇)になったから扱いが簡単になるわけではなく、むしろ距離の場合はベクトルの取り扱い方が使えるところ、0/1 の XOR では取り扱いが手探りになって頭がバグりがち。だから最初の提出ではいったん根からの距離を求めた上でその偶奇を利用するように途中から方針転換したんだけど、すでにバグっていた頭は根からの距離の計算もバグらせた。どっちでやってもバグらせたので AC 提出では当初の方針通り 0/1 の XOR を UnionFind に載せた。連結成分内の辺の数をわざわざ記録したけど、まとめて辺の総数(M)を引くのでいいらしい。■E 問題はもう種明かしを見てしまったので D 問題の UF 実装から難しい部分を取り除くだけでおしまい。提出 #37379631 (AC / 341 Byte / 296 ms)。■D 問題。頭がバグるなら BFS/DFS でやるなり頂点を倍加して普通の UnionFind をするなり(「偶数世界と奇数世界?」)、やりようがあったらしい。しかしまあ、バグる頭は足りない頭でもあるわけで。■F 問題。「FはSparse Tableを作れと書いてある」らしい。たしか蟻本でセグメント木、BIT に続けて紹介されていたのが Sparse Table だった。よくわからなかったので見なかったことにしたが。■蟻本を読み直した@風呂。セグメント木と BIT のあいだのコラムで Sparse Table が紹介されていた。こういうときに使うんだ、という強みが見えない紹介のされ方だったのであまり理解する努力をしなかったのだ。F 問題の解答を踏まえると Sparse Table のココロがわかった。BIT と比較するとメモリ消費が大きくて、ということは初期化と更新に時間がかかるということ。更新は区間幅(2べき)の和でフルビット(N)だろうか。取得に関して、BIT が対数個の要素を参照しなければいけないところ、Sparse Table は2個の参照で済む。しかしどの要素を参照するかを知るために前後の2べきを求めるのにビット長の線形時間(競プロ的には対数時間だったり「log は定数」だったりする時間)をかけると有利が消える。ビルトインの clz (count leading zeroes) が使えるとビット長の対数時間で2べきが求まったりするの? なんか上手い配置があったりするの? そんな感じで、参照に有利な条件が整っているときに強みがあるのが Sparse Table だと思いました。優先度は低いよなあ。■『ハッカーのたのしみ』を開いた。CLZ 相当の命令がある場合があるらしい。ということは __builtin_clz は「悪くて」ビット長の対数時間ということなん? 1命令のコストとかそのレベルからは「すんごく速そう」以外の感想はない。2 人ともが話すことの出来る言語が存在する」ことと「
2 人ともが X とコミュニケーションを取ることが出来る」ことの違いをよく意識しなければいけない。2つの条件でそれぞれ使われている「共通言語が存在する」ことと「コミュニケーションが取れる」ことはイコールではない。共通言語の存在は再帰関数の停止条件であり、コミュニケーションが取れることは共通言語の存在により再帰的に定義されている。後になって問題を反芻していたとき、X 以外の別の人間を介在させてコミュニケーションが取れると判断してはいけない気がして、なんで AC だったのか疑問に思って問題を読み直して、表現の違いに気がついたのだった。■なんだかんだで青 diff が半分くらい埋まってきてるので、そろそろ青入りさせてくれてもいいんですよ。
8772053214553.691
な一方、出力例が 8772053214538.5976562500
となっている。差は 15 とちょっと。これが「出力は、真の値との絶対誤差または相対誤差が 1e-6 以下のとき正解」という条件を満たすかどうかの判断がひとつの分かれ目だったらしい。自分は何か月か前あたりに、絶対誤差と相対誤差を正確に計るとこういう式になるのだけど……(でも必ずしも停止条件を厳密に計る必要はないよね)、的な文章を読んでいて、大きい値の相対誤差は(絶対値的には)そこそこ大きい値でも許されるんだなあ、というような、今では式もよく覚えてないけど意外性の発見があったことだけは覚えていたので、通るような予感があった。祈りながら提出して 1 WA でも返ってきたらどうしようもないなと戦々恐々としていたのも本当のところだけど。解法は g を探索する整数の二分探索(Range#bsearch)。だけど g におけるタイムと g+1 におけるタイムを比較して判定条件にしたので実質的には三分探索だった。こんなに簡単素直な解法でいいのかと疑ったけど、20210401p01.03 に書いたように ABC174-E「Logs」が自分が初めて解いた解を二分探索する問題で、二分探索に対する発想の転換があるまでは解けなかったことを思い出すと、D 問題でこの素直さはありなのかなあとも思った。早々に解析解を提出している人はすごいね。分数とかルートとか、もはや紙と鉛筆があってもなんとかなる気がしない。■E 問題「Cheating Amidakuji」(水 diff)。題意を理解するのがちょっと難しい。ざっくり言うと、A 数列の値に従って B 数列の隣接2要素のスワップを繰り返したとき、B 数列の要素1がどこへ移動するかを追跡する。A 数列の要素の1つを無視した場合(スワップを1つ飛ばした場合)の答えを A 数列の長さと同じ数だけ答えてね、という問題。スワップ対象の
B_{A_k+1}
が B_{A_{k+1}}
と紛らわしくなかった? HTML ソースを読んで判断したよ。結局は同じことをしているのかもしれないけど、人によって全然解法の背景にある考え方が違いそうな気がする。自分はといえば、まず最初に A 数列を順番に使用して B 数列のスワップを最後まで完了させた。そして B 数列の初期位置と最終位置の対応を記録した。そして B 数列を初期化してからもう一度スワップを繰り返した。その際に、A 数列のこの要素が関わるスワップを飛ばしたとしたら答えにどう影響するかを考えた。スワップする2つの要素がどちらも1ではなかったら、1の最終位置は変化しない。どちらかが1なら……。■■■@2022-12-07 F 問題を振り返ってなかった。F 問題はボールから箱を引くデータと、箱から箱ラベルを引くデータと、箱ラベルから箱を引く3つのデータを用意した。最初からこの方針だったのだけど、Find 関数の停止条件が明らかではなかったり、箱と箱ラベルを混同したりでなかなかサンプルが合わせられなかった。合ったら合ったで TLE だったしね。箱というのが普段の UnionFind で取り扱う頂点なのだけど、この問題では箱が表に出て来ない。ボールや箱ラベルから間接的に参照されている。こういうのは初めてだったし、要件に対して用意するのがこの3つのデータで間違いないという確信も持てないまま実装していた。自分としては ABC273-E「Notebook」(青 diff) を解いたときと同じ頭の部分を使っていたのであり、そのときみたいにさささっと8分で解きたかった>20221015。でもこっちの問題は骨格を決めた後の実装がちょっとややこしかったね。