競プロ備忘録

競プロerの備忘録

ARC151B - A < AP

結構迷走しながら考察しましたが、何とか解けました。
解説見たらめちゃくちゃ賢い解法が書いてあってビビりましたが、自分の賢くない解法も残します。

解法

 1 \le i \le Nである各 iについて、 i P _ {i}の間に辺を張った N頂点の無向グラフの連結成分を考える。
まず、すべての連結成分の頂点数が 1であるならば、解は 0になる。(すべての i A _ {i} = A _ {P _ {i}}となり、辞書順が常に一致するため。)
そうでないとき、すべての連結成分について、連結成分内の頂点数を並べた配列を作り、次のようなDPを考える。

 DP _ {i, j} := i 番目の連結成分までみたとき、 j = 0であれば辞書順で Aより小さいことがすでに確定しており、 j = 1であれば、辞書順で Aと等しいような場合の数

つまるところ、桁DPのようなことをする。 ここで Sizeを連結成分 i内の頂点数とすると、このDPの更新は以下のようになる。( Rについては後述)

 \displaystyle
DP _ {i+1, j} = \left\{
\begin{array}{ll}
DP _ {i, 1} * R + DP _ {i, 0} * M^{Size}   &   (j = 0)  \\
DP _ {i, 1} * M        &   (j = 1)
\end{array}
\right.


式中の Rについては、連結成分内で条件通りに数字を並べる場合の数である。
これはある連続する2つの数を見たとき、その部分が増加していて、それ以前は連続する数の1つ目の数と同じ数が並び、それ以後はどんな並び方をしていても良い場合の数とも言える。
例えば、入力を N = 4, M = 3, P = [2, 3, 4, 1]とすると、すべての iが同じ連結成分に属し、 Aは以下のような並び方が考えられる。( *は、 1 から 3まで何が並んでいても良い。)

  •  1, 1, 1, 2
  •  1, 1, 1, 3
  •  1, 1, 2, *
  •  1, 1, 3, *
  •  1, 2, *, *
  •  1, 3, *, *
  •  2, 2, 2, 3
  •  2, 2, 3, *
  •  2, 3, *, *

つまり、 Rは、 R = {} _ {M} C _ {2} \sum _ {i = 0} ^ {Size - 1} M ^ {i}と求められる。
 Sizeの合計は Nなので、上記式は愚直に計算しても O(N)の時間計算量で求まる。また、連結成分ごとの頂点数を求めるのにはUnionFind木を用いたり、連結リストをたどるようにして求めれば、 O(N)かその定数倍とみなせる計算量で求めることが出来る。
そのため、全体として O(N)の時間計算量で解を求めることが出来る。

コードは以下の通り。(実装の問題でlogがついたりしてますが、気にしないでください)

Submission #35733069 - AtCoder Regular Contest 151