ABC214

5完。CDが難しかった。GHは読んだだけ。最近のABCは露骨な「○○法を使う問題」ばかりだったが、久しぶりにいつものABCという雰囲気だった。特にDの考察難度の高さが好き。

A - New Generation ABC

問題文中にある数値をコピペする。コピペする2つは126と212だ。あまり好きではないタイプの問題。

B - How many?

怖い見た目だが、100まででいいから全探索できる。0を含むので掛け算して減ることがあり、本当に全探索したほうが安全。

C - Distribution

問題文が意味不明。さすがにしばらく経つとわかってくるけど。高橋君と隣のすぬけ君両方から同時にもらうこともあるよね。順番に最小値更新しながらというのを思いつくが、いやもらう順に処理しないとダメではと思い直す。しかし結局それでよかった(隣からもらう最速はそれでわかるので)。円になっているので2周する。直線ならどうかとかも考えたけど、そこから難しかったんだね。その難しさが円で隠されているのが本当にきつい。難易度的にはDでもいい気はするが、よくある考え方の典型だからCに置きたい気持ちはわかる。

灰diffで草。天才の集まりか?w

(解説を見て)いやグラフの最短経路問題と見ることができるのかよ。言われてみれば。宝石の立場でダイクストラ法かあ。

D - Sum of Maximum Weights

これも難しい。今ならEでもよさそう。まず、各辺の寄与を考えてみる。一番wが大きい辺は簡単で、両側にある頂点の個数の積、よくあるやつだ。しかし2番目からが計算量的に無理そう。しばらく考えて、UnionFindでこの操作の逆ができそうなことに気づく。最も小さい辺の寄与はその1個だけ。2番目も、1番目と隣り合っていなければ1個だけ。今までに選んだ辺(の両端の頂点たち)とつながったとき、新しい連結成分内のパスの個数は普通に計算できて、それまでの個数を引けばその辺が何回数えられるかわかる。UnionFindで連結成分毎に、今までにカウントしたパスの個数を持っておけばいい(改めて考えると、それは単にパスの個数だから保存しなくてもその場で連結成分のサイズから計算できた)。

小さい順にソートするのを忘れて1WA。いつもサンプルに頼りっきりだから、たまたまサンプルが通るときはこうなってしまう。見直しするのも、それでミスが見つかるのは稀だから、ペナ込みタイムの期待値としては別に改善しなさそうなんだよなあ。そうなると、さっさと提出して難しい問題を考える時間を少しでも残したほうがいいということになる。

E - Packing Under Range Regulations

難しいけど、Fには置けないよなあ。方針はわりと短い時間で見えた。まずLでソートして、Lが最小のものたちを見て、一番左に置けるのはそいつらだけだから置いて損しない。複数あるときの選び方は、Rが最小のものとして損しない(他が全部上位互換なので)。さて、1個目は決まった。すると、2個目からもほぼ同様に選べる。「ほぼ」というのが何かというと、同じ箱は選べないので1個目とLが同じものはLが1増えた感じになる。ソートやpriority_queueではそのLの書き換えが計算量的にはっきりしない。LでソートしてからRでpriority_queueを使えば大丈夫そうだ。この実装が難しすぎて発狂しそうになった。実はもっと楽なんじゃないかとか思ってRでソートして小さい順に見たりしたけどはっきりしないので、やはり元の方針がはっきり解けている。

次どの箱に入れるかの変数L1を持ち、それと等しいものを全部priority_queueに入れる。一番Rが小さいものをpopして、区間がL1を含むかチェック。L1をインクリメント。以下繰り返しだが、キューが空になったら改めてL1を残っている最小のLに設定する、空になって入れるものも残ってなかったら処理は完了。この流れが見えなかった。これは1ループでボールを1個箱に入れてるけど、最初は1ループでボールを1個キューに入れていた。何をしたいかわかっているつもりなのにコードに落ちないのは、普段だったら楽しいけど、コンテスト中は何もできずびゅんびゅん時間だけ過ぎてつらい。

F - Substrings

まあDPが相場かなという見た目。どんなDPだよって話で、これはかなり後になってから気づいたのだが、i文字目までで(最後の文字とか最後に使った文字の位置とか毎に)何通りかがわかってもi+5文字目とかで合流して同じ文字列になることもあるので、普通のやり方ではうまくまとめることができない。ABC211Cみたいに考えて、全パターンをうまくまとめてとかも思ったけどまあできない。最後のほうで気づいたのが、ランレングス。例えばaが5個並んでたら個数だけが重要でどのaを選んだかは区別できない。これは本質っぽい。だが、aabccabaaみたいので間のa以外の文字を何も使わなかったときaが連結してしまうし連結の仕方も色々なパターンがあるしでまとまらなかった。DPで左からやれそうだと最初は思ったんだけど、思いが間違っていたかとは関係なく、思いと現実がぶつかってクラッシュしてしまった。うまくいかない。

(追記)ABC171Fの考え方を使う(これコンテスト中にわりと短い時間で解いてるんだけど当時の自分に勝てる気がしない)。印のつけ方(残す文字の決め方)について、左から見ていって貪欲に一致する文字を取っていくことにする。こうすることで取れなくなることはないし、これで印のつけ方と「Tとしてありうる文字列」が一対一対応する。最後に選んだ文字の位置それぞれについて何通りかを左から求めていくDPをする。現在見ている位置の文字がaなら、直前のaよりも前(左)の文字からつなげることはできない(代わりに直前のaを選ぶルールだった)。それ以外はOKというのが難しいが、ルールに沿ってその通り数なのだからその文字から見て初めてのaなら問題ない。あとは求めた値で累積和を作り、各英小文字について直前に現れた位置を持っておけば、DPの更新は高速にできる。この問題だと連続した文字は選べないが、そうするとなんか1ずれる(同様の考え方でいいが、ここも難しかった)。考察にいくつか分岐があり解けるものを選んでもすぐにそれとわからないため時間がかかった。

G - Three Permutations

(追記)攪乱順列のすごいやつ。解く気が起きない見た目。解説を見ても何もわからない。解説読んで自分で考えて解説放送見てを繰り返すことでどうにか進むことができた。各iについてp_iとq_iの少なくとも片方に一致するかを考えて2^N通りに分ける。例えば p_i=3, q_i=5 だったら p_j=5 となるような位置と競合してて、追っていくとサイクルになるらしい。このサイクルたちのそれぞれの長さだけが重要。各長さについて、pqと一致するr_iをいくつか確定させる方法が何通りあるか数える。前後どちらと一致させるかあるいは確定させないかで3通り、同じ数を複数使うのはダメ。円環なので最初だけ3通り仮置きしてからDP。DPで個数を状態として持っておくことで、何個確定させるのが何通りというのがわかる。これを各サイクルについて畳み込みみたいに合併させていくと、全体で各確定個数が何通りか求まる。あとは未確定のぶんを階乗掛けて、普通に包除原理(2^N通りのうち、確定0個のものを足して1個の合計を引いて...という感じ)。コードが出来上がってみると、ちゃんとp=qのとき攪乱順列の個数が求まっている。考察の各ステップが400点くらいの難易度で、しかもそれを「こう考えたらどうかな」という偵察パートで(将棋でいう読みの深い場所で)ある程度どんな部分問題か判定する必要があり、長い時間をかけて解説を理解していった(進捗がないと集中力が続かないので休んでいた時間が支配的ではある)。最初のころは「これがわかるときが来るのか?」と気が遠くなるような思いだったが、今日(金曜日)ようやくACできてよかった。

H - Collecting

(追記)とりあえずSCCだけど、解ける見た目をしていなかった。最小費用流と知ってから考えると負辺があっていいならできた。そして解説を見ると、なるほどDAGだからトポロジカルソートして、ある辺でスキップした頂点たちが区間になるのかあ。元のグラフの辺をSCCしてできたグラフの辺に対応させる処理が(簡単ではあるけど)慣れなくて手間取った(辺はそのまま保存しておいて頂点を対応付けるだけ)。