ABC321

6完。今回も頭が悪かった。問題は面白かった。

A - 321-like Checker

文字列として受け取ってN-1回文字として比較。

B - Cutoff

長さN-1のvectorを用意しておいて、それをコピーして1個加えてソート。全探索できますかという問題。いいね。

C - 321-like Searcher

DFSすると1024個しかない。0が2個ある理由がわかってなかった。出力させてみて、最後に降順じゃない意味不明な値がある理由がわからなかった。いつまで考えていても仕方ないので提出したが、WA。9876543210の先頭が9なので9桁と思い込んでいた。2^10なのは終了後にツイートを見て知った。それまで全く気づかなかった。9876543210の部分列が2^10通りで、無と0を除いた1022通りになるんだなあ。

Fを終了2分前ACしたんだけど、ここでペナを支払って時間を得たのが単純計算では大きかったことになる。

D - Set Menu

Pでmin取られちゃうのが難所。とりあえずソートはするんだけど、そうすると二分探索できるというか、しゃくとりみたいにしてソートの他は線形でできる。Aの大きい順に見て、どこまでP未満かを更新していく(延ばしていく)。P未満になる区間のBの和も更新する必要があると実装して気づいた。その情報があればあとは掛け算で求まる。

E - Complete Binary Tree

FG辺りの見た目してる。実際けっこうきつい。構造はセグ木のやつ。X=1ならできるので、帰着させたりできないかなとか思ったけどできない。1個ずつ親に移動しながらやる?ダブってカウントされるのがかなり厄介そうに見えたが、自分から見て親の自分じゃないほうの子の下を数えればいい。頂点1じゃなくても、下りれるだけ下りてその層に何個あるか求めれば子孫のみの答えはわかる(頂点Nがこの範囲にないことがあるのが頂点1以外から考えるときの難しさ)。これでおおむね解けたが、ここからが(時間的に)長かった。まず、親じゃなくてその子から数えるのを忘れている。兄弟は2親等だから最初はKから2引かないといけないのに気づかない。親自身もカウントしないといけないからこの実装だとK=-1のときも1を足す必要があり。見落としの一つ一つに時間がかかった。

logは2つ付いてしまうがまあ大丈夫だろうと思っていて実際大丈夫だったが、なるほど深さは最初に1回求めるだけでいいのか。「頂点1以外から考えるときの難しさ」に圧されたままでわかってなかった。確かに2区間の共通部分を求めるだけでいい。

(追記)解説を見て引き算する方針で実装してみる。区間の共通部分を求めるときminとmaxが逆だった。Gでcountl_zeroを31から引いていたので同じにしてしまったが63から引かないといけなかった。時間がかかった。

F - #(subset sum = K) with Add and Erase

わからない。このまま何もせず時間をすごしてもしょうがないので、とりあえず普通のDPを書く。+しかないのならDPを付け足していくだけ。-は無理では?構造が木みたいになって+の処理だけにできるのかとも思ったけど、でかいやつの色々な位置を1個だけ変更とかされたらどうしようもない。順位表を見て短時間で通してる人も多いのはわかっていたが。どうにか差分計算しようとして、あのときあの遷移がなかったらというのを考えて、戻すことを思いつく。Kより大きい領域が必要な気がしてならなかったが、必要なかった。ずらして重ねて足す図を描くと、離れている場合はできて、近い場合は下のほうはできてそこからもできる見た目をしている。てきとうに引き算して最初はサンプル合わなかったが、in-placeでやったほうがいいやつだった(こういうときにかぎって)。サンプル合ったので即提出、AC。

こんな操作ができるかつそれを知らないって、競プロやってなかったのでは?戻すDPってこういうのかあ。

G - Electric Circuit

(追記)難しかった。解説の「期待値の線形性」のところ気づいてなかった。ある頂点集合について、辺がその集合内で完結してるのが何通りかは、赤青の個数が一致しているかと階乗でわかる。あとは小さいほうから引き算だけど、ダメなケースを過不足なく数えるには集合内の番号が最大の頂点を含む連結成分を列挙すればいい。細かいところがなんもわかってなくてサンプル合わないを繰り返していた(最近のよくない傾向)。popcountを使おうとし続けていたが、そうじゃなくて赤青の個数が重要だ。各頂点集合についてDPで赤青の個数を求めておく。階乗はMまで前計算しておく。各頂点集合について、集合内のつなぎ方だけ見て連結成分が1個になるのが何通りか求めていく。番号が最大の頂点を含む部分集合の通り数と残りの頂点数の階乗を掛けて引いていく。求まったらその集合に含まれないやつのぶんを掛けて足していってMの階乗で割って答え。