AGC 028 B - Removing Blocks

解法

まず, とても愚直な方法を試すと, おそらく O(N^2N!)の計算量になると思います(next_permutationを用いて取り出す順番を決め,(O(N!)), 一つ取り出すごとに隣接するブロックのコストを合算する計算(O(N))をO(N)回ほど繰り返すので.). 制約をみると, とても愚直な方法は間に合いそうにありません.

そこで, 『あるブロックのコストが何回足されるか』に着目してみます.
ある位置のブロックのコストが何度足されるかだけを考え, 後で掛けあわせます.

あるブロックというものをj番目のブロックとしておきましょう.
このブロックのコストが合算されるときは, あるi番目のブロックを抜いたときの, 次のような場合のときです.

  1. j番目のブロックを取り除くとき.
  2. i番目(i < j)のブロックを取り除いたとき,  i ~ jまでのブロックが取り除かれていないとき.
  3. i番目(j < i)のブロックを取り除いたとき,  j ~ iまでのブロックが取り除かれていないとき.

以上の3つの場合があります.
それぞれの場合が, どれだけN!に含まれているかを考察します.
まず, 1の場合を考えてみましょう.
この場合は簡単で, どの取り除き方にしても 最終的にすべてのブロックを取り除くことになるため, N!通りの場合が存在することがわかります.
2の場合を考えてみましょう.
あるi番目のブロックを取り除いたとき, j番目までブロックが取り除かれていない, ということは『i番目からj番目までのブロックの中で, はじめて取り除くのがi番目のブロックである』ということと同値です.
そこで,
N!通りある取り除き方のうち, ijまでのj-i+1個のブロックの中で初めて取り除くのがi番目のブロックである場合の数はいくつか?』を考えることができます.
取り除き方が一様であることを加味すると, この場合の数は\frac{N!}{j-i+1}となることがわかります.
言い方を変えると, 『N!通りある取り除き方のうち, ijまでのj-i+1個のブロックの中で初めて取り除くのがi番目のブロックである取り除き方の割合は\frac{1}{j-i+1}である.』とも言えます.(公式ではそのような解説でした.)

2がわかると3も同様で, こちらも場合の数は\frac{N!}{i-j+1}となります.

以上により, 各i,jについて1,2,3を合算するとO(N^2)の解法を得ることができます. 具体的には, あるjについて,  i0 \leq i \leq Nまで回してブロックの足される回数を数えたあと, A_jを掛けあわせ, 答えに足し合わせる, ということします.
計算をする際は, フェルマーの小定理で逆元を計算して掛け算をしましょう.

O(N^2)O(N)にするには, ブロックの足される回数の割合が規則的であること(単純に分母が1ずつ減ったり増えたりしています)を利用して, O(1)でブロックの足される回数を数えることができるように逆元の累積和(\frac{1}{1} + \frac{1}{2} + \frac{1}{3} ... )を取っておけばよいです.
答えはMODをとっているので, あくまで逆元の累積和であることに注意してください (割り算を掛け算で実装する必要があります. )

感想

えーおもいつかない
数え上げの問題で割合を利用するってのは新鮮ですね