ABC340

6完。調子は悪くないと思うけど、結果が出ないね。特に反省点がない。いつもは前半の問題でも得るものがあるんだけどな。

A - Arithmetic Progression

むずすぎないかと思うが、for文でそのまま書ける形だと気づいて解決。cout << i << " \n"[i == b]; と書くんだけど、この[i == b]の部分を最初思いつかなくて別の実装に行っていた。これは1分切れる問題だった。実装力がない。

B - Append

数列Aをvectorで持つ。

C - Divide and Divide

手で実験して、N*log(N)くらいの答えになるだろうけど思ったより規則性が見えず困る。しかし、分解された数たちは高々1くらいしか違わず、これは例のメモ化再帰でできそうだと気づく。他の方法が全然見えないのでそれを実装する。答えは64bit符号付き整数(Nの90倍くらいまで扱える)に収まりそう。x円を足してないとかメモしてないとか実装がボロボロだったがサンプルに助けてもらいAC。

D - Super Takahashi Bros.

ステージX_iへ飛べるというのが異質なのでそこに注目する。DPを高速化かなあと思って考えていると、やはりそのX_iへのジャンプがやばすぎて、ああダイクストラかとなった。D問題でこの見た目からの、ただのダイクストラ法、かなり意外だった。

E - Mancala 2

操作で何をやっているのかを見ると、指定された箱からボールを全部取ってその次の箱から1個ずつ配っている。区間加算ができればいいので遅延セグ木で解けそうだが、もう少し考えると他に必要なのは1点取得なのでBITを使えばいいと気づく。いもす法をBITでやると区間加算1点取得ができる。ライブラリにしたほうがいいかもしれない。実装上のポイントとしては、(0-indexedで)位置Nは使わないのでそこへは足しても足さなくてもいい、区間加算で単純に終端の位置を計算してNより大きいならNを引いて0からそこまでも足す。

(追記)ライブラリにしようと書いたら、思ったより楽にならない。まあ区間をちゃんと考えるのが本質の一つっぽいもんな。でも書いた。同じ値を符号を変えて書くのはやはりよくない。まとめたほうがいい。

F - S = 1

サンプル1を考えると、(0, 0)と(3, 5)を通る直線との距離が1/sqrt(34)になる格子点を見つける問題になる。絶対値が10^18を超えるとかあるのかなとか思いながら。で、ベクトルで考えて90度回転させた(5, -3)が長さsqrt(34)だからちょうど1/34倍にすれば合う。(5/34, -3/34)を通ってさっきの直線と平行な直線上の格子点を見つけたい。なんか64bit整数では無理そうだしそもそも何も見えないし。ここで順位表を見るとけっこう簡単な解法がありそうに思える。あー単に外積で面積求まるじゃん。外積の絶対値が2になればいい。しかもこれはまんまextgcdの形をしている。たしか、与えた数より絶対値が大きくはならなかったと思うので、10^18以下という条件もまあ大丈夫そう。gcdが2「を」割り切るなら面積1の三角形が作れて、そうでないなら作れない。符号が逆になると三角形がどうなるのかイメージできておらず、線対称な位置に格子点があるとは限らないよなと思っていたが、点対称だった。ある程度周辺理解を深めてから提出(最初なんもわかってなかった)。

G - Leaf Color

考えているうちにGが木であるという条件が抜けている。必要だと思って、誘導部分グラフに辺がない選び方を数えるDPを書いてしまった。それだと(空集合の1を引いて)答えより小さくなるはずだがそうなってなくて誤読に気づいた。これ誤読っていうのかな。確かに見たけど抜けている。忘れたという表現も違う気がする。問題が難しいと考えてるうちに抜ける。気づいたときには残り10分。

次数が0の頂点があるのはGが1頂点のときだけでそれはN通り。それ以外のときを考えればいい。2頂点以上の木には葉が2個以上ある。色を固定するとその色以外が次数1であってはならない。DPできそうな気もするけど、全部の色をいっぺんにやる方法は見えないね。

(追記)色毎にDPするのもけっこう難しい。Gが木となるとき、G内で(頂点1を根とする木で)深さの値が最も小さい頂点が一意に定まるので、そこで数える。木G内の部分木について、根以外の葉が全てその色である通り数でDP。子の部分木がx通りだったら、x通りのどれかを選ぶかその部分木を使わないかでx+1通り。これを掛け算する。最後に、根がその色でない場合は根だけを選んだとき条件満たさないので1を引く。また、答えへの寄与は、根がその色でないときだけ根の次数が1(ちょうど一つの子を使う)の場合を除けばよい。ここで、1頂点からなる木は(重複が面倒なので)カウントしないことにする(この方法では常にカウントされているので1を引けばよい)(別のところでまとめてNを足す)。

Auxiliary Treeの構築が異常に難しい。対象の頂点たちを行きがけ順でソートするところまでは典型90の35でやってあった。スタックを使って頂点を1個ずつ追加していく。1個追加したら、追加した頂点の次の頂点とのLCAを求め、スタックのtopがLCAになるまでpopしていく。popしたとき、スタックにLCA以上の深さの頂点がなければLCAをpushして(この横入りをどうコードにするか全く見えなかった)、topからpopした頂点へ辺を張る。次の頂点がなくなったら単にpopしながら辺を張って、最後に残ったのが根。