ABC266

6完。内容的には自分なりに満足という感じだが、レーティング1900を割ってしまった。

A - Middle Letter

いいA問題だ。長さを2で割れば中央のインデックスが得られる。

B - Modulo Number

x以下の最もxに近いmの倍数を返す関数を持っているのでそれを貼る。探すのに時間食ってしまった。直接求まるわけではないので、まあNから引けばいいんだけど、そこも少し時間使った。これも自分にとっては(実装軽くて)いい問題(適正レベルの人に対してはやや難しいか?)。

C - Convex Quadrilateral

各頂点について、どっちに曲がっているか調べる。注目している頂点から見た隣の頂点の位置を表すベクトルの外積をとり、とりあえずサンプルで符号を見てそれに合わせて判定を書く。一つでも逆の符号があったらダメ(制約で0がないことは保証されている)。これもわりと軽めだったのでよかった。ただ、C問題としてはかなり高度。

D - Snuke Panic (1D)

全然わからない。ということはDPだ。実際DPできた。整数時刻に整数座標にいるとしていいか証明できなかったが、コンテスト中はいくつかの例を考えて済ました。穴から出てくる時刻だけ考えて、前の時刻と今の時刻の差で移動距離の上限がわかる。25通りの遷移を全部やる。可能な移動元の最大に、もしちょうど出てくる場所にいるならその大きさを足す。長さ5のDPテーブルを2つ使うだけの省メモリ。

解説見て気づいたけどT_Nが10^5以下なの完全に忘れてた(ちゃんと読んで認識していたけど見つけたのが10^9でも解ける方針だったから「都合よく」忘れてしまった)。

E - Throwing the Die

後ろから。最初は3.5で、次はそれ未満の出目なら続ける。6通りの出目の期待値の平均をとればよくて、それをN回回す。かんたん。

F - Well-defined Path Queries on a Namori

なもりグラフは、ループにひげ(木)が0個以上付いてるやつ。まず閉路検出。無向グラフなので、DFSで祖先に当たったらそこがループ(祖先でない訪問済みの頂点に当たることはない)。祖先の頂点番号を記録しておき、そこに戻るまで親に印を付けていく。これで閉路に含まれる頂点を列挙できた。次に、パスが一意になるかを場合分けして考える。どちらも閉路に含まれているなら2通りある。片方だけ含まれている場合は、閉路の中を移動するかどうかで違いそう。どちらも含まれないなら1通りかと思いきや、閉路の中を通過するやつは2通りある(かすっただけでは1通り)。2通りを超えてありえるかは知らんけどそこは関係ない。閉路に含まれる頂点を2個以上通ったらそこを閉路の反対側に置き換えることで別のパスになる。そうでないなら、0個は明らかに無理だし1個も無理そう。未証明だが実装に入る。

DFS木で考えて、セグ木でLCAを求める。まず閉路に含まれる頂点を求め、それを使って自分を含めた祖先たちに閉路に含まれる頂点が何個あるかもう1回DFSで求める。クエリに対しては、LCAを求めて引き算とかすればDFS木上のパスに含まれる個数がわかる。それが2未満ならYes。が、全然サンプルが合わない。プログラムが落ちることもある。なもりグラフを木のように扱うのが思ったより厄介。まず閉路検出のDFSでループに反対側から入るのを抑制していなかった。その後のDFSも、単にループ検出したときの辺を使用不能にするだけでいいのに迷走していた。それでも合わない。なんと、自分の以前の提出からコピーしてきたら、lcaという名前の関数がLCAの頂点番号ではなくパスの長さを返していた。これは反省せざるをえない。まあLCAって苦手なんだよな。

解説見たらとてもシンプルだった。これはなあ。力不足と言えばそうなんだけど。シンプルな解放を目指すべきなんだよな。にしてもこれを1000人解いてるのはやばいだろ。

G - Yet Another RGB Sequence

Fの実装で詰まったとき読むだけ読んだ。Fを通したあとで考えたが難しい。包除っぽいけど、指定したRG以外のRGが被ってくるのをどうしようもない。

(追記)解説見るとわりと簡単だった。ARCっぽいよな。解説見ちゃうとその通り実装するだけで勉強してる感じがしない。RとRGとBを好きに並べてそこへ(RGを作らないように)Gを入れるのが何通りあるか。Rが1個あるたびに入れる場所が1個減る。0個以上好きな個数入れていい場所がいくつあるかという意味でRを取り除いたときと同じだ。