ARC108

4完。Aが案外簡単だったことで緊張は解けた。最近好調なのは、出題傾向が2年前のAtCoderに戻ってきてる?ratedコンテストが多いので、yukicoderに出る回数を減らしてモチベを保とうとしている。

A - Sum and Product

怖そうな見た目だけど約数列挙の形にすればいいやつだ。判定問題なのがいいひっかけになってる。10^12ってそういう意味だったのか。

B - Abbreviate Fox

fofoxxみたいのが問題。次に、どんな順に取り除いても操作ができなくなったときの長さは同じかが問題。貪欲に取り除くのをリスト構造でやるか、前から文字をカウントしてできないか、DPでできないか。DPを考えていたときに、スタックに文字を入れてって末尾がfoxになったら取り除くのを思いついた(括弧の問題でよくある)。それで正しい答えが求まることの証明は実装が終わってもできないまま。さすがに提出した。AC。

括弧みたいに考えればいいのかな。foやoxのつながりが操作によって切れることはなく、fの次がo以外なら対応するoまでの間が全部除かれる必要がある。

C - Keep Graph Connected

サンプルが1個しかない。Noのサンプルがない。それを踏まえて考えていく。辺を削除するって書いてあったの忘れて、削除せずに条件を満たす書き込み方があるかを考えてた。勘違いに気づいて、じゃあ全域木を考えればよさそうと思い、常に条件を満たしそうだと気づく。「よい書き込み方」であるためには連結でありさえすればいい、つまりある全域木が残る書き込み方なら他に辺がたくさん残るぶんには問題ない。ここらで気づいたけど、Noは出力させる気がないからこんなぞんざいな書き方なのね。

UnionFindを使い全域木を作るか、DFSの探索木を使うか。前者のほうが慣れた処理だが、実装が簡潔になりそうな後者を選んだ。DFSして、自分と子へ伸びる辺が同じなら子はそれ以外の数、違うなら子は辺と同じ数を書き込む。それで根は直接つながるどの辺とも違う数にしないといけないかなとか思ってた。一応1以上N以下のN通り書き込めて、辺は最大でN-1本なので必ずどれとも違う数を選べる。やや煩雑なのでもう少し考えると、子が全部調整してくれるので親に書き込む数はどうでもいいと気づいた。DFSの再帰関数でお前はこの数というのを渡せば、子へ行くときに自分と辺が同じかで分岐するだけ(違う数にするときは1を足すのが簡単そう(0-indexedで実装してるので剰余をとってNは0にする))。結果的に、グラフを受け取ってDFSするだけというきれいなコードになった。この時点で順位がいいのは珍しく、嬉しかった。

D - AB

ソースに書く考察コメントをずっと // でやっていたが、今回ようやく /* */ を使った(毎行 // を入力する必要がないしIDEの補完も利くからよかった)。つかみどころのない問題で、あまりやりたくないと思った。順位表と問題文を見てEも難しそうなので仕方なくDを考え続ける。最近やる気がないのでこういうときいい感じに力が抜けて(順位表とかながめてのんびりしたりして(もちろんその際は問題の内容を頭に入れてちょっとでも詰まるまで考えてから))体力を節約できる気がする。長さNの文字列から減らしたり、DPできないか考えたりしていたが、うまくいかず。

AAAAやBBBBは1通りなので場合分けを考えてみる。まずC_ABによって初手は確定。対称性からC_ABはAとしてよい(具体的に同じ意味へ変換するのはややこしいけど(全部反転してからC_AAとC_BBをswapしたけどほんとか?))。さて、C_AAがAならやはりAしか増やせず簡単。C_AAがBとすると、ABABが現れる。C_BAの出番だが、これがBだとBを増やせるのでA...ABの形であれば何でも作れる(これは2冪で簡単)。C_BAがAだと連続するBが作れなくなる。これで意外なことに解けていそう。残り時間が20分を切ってきてたと思う。場合分けがちゃんとできてるかも不安だがとにかく書くしかない。連続するBがないとき何通りある。わからない。でも思考停止DPならできるのでは?できる。得意ではないがさすがにここまで簡単なDPなら時間内に書ける。明らかに有名なやつだけど、それはおいといてDPを書く。書き上がって、残り8分でAC。余裕はあったけど、ここまでノンペナは運もよかったと思う。