AGC028 B問題
AtCoder Grand Contest 028のB問題を解いた。
時間内には解けなかったし、解説もよくわからなかった。
問題はこれ
B - Removing Blocks。
解説はこれ
https://img.atcoder.jp/agc028/editorial.pdf。
参考にしたのはこれ
AGC028 B問題 Removing Blocks - banbooooのブログ。
解説
解説でよく使われる確率を理解できたことが殆どなかった。
今回もそれ。
いろいろ調べてたら上の参考サイトを見つけた。
解説などに置ける、同様に確からしい確率は確率を表しているわけでなく、
背反な事象でそれぞれの個数が等しいもののことを言っているということがわかった。
数学っぽく言うと、数え上げ測度の等しい disjoint な可測集合たちのことを言っていることがわかった。
とはいえ、確率の気持ちで理解するのは大事っぽい。
同様に確からしいっぽい気持ちで考える問題もよく見る。
解説をします。
i番目のブロックを取り除いたとき、j番目のブロックの値が加算されるとする。
i番目からj番目までのブロックがどれも除かれておらず、その中で、i番目のブロックが初めに取り除かれる場合の数を求めれば良い。
が成り立つ。
互いに排反なので、
となる。
また、(同様に確からしいの部分だが、)各に対して、
は等しい。
従って、どのに対しても、
となる。
特に、今はの場合である。
あとは、色んなサイト書いてあるように、累積和とかmodにおける逆元とか頑張ればできる。
プログラムは次のやつ。
def getInv(N): inv = [0] * (N + 1) inv[1] = 1 for i in range(2, N + 1): inv[i] = (-(Q // i) * inv[Q % i]) % Q return inv from itertools import accumulate N = int( input()) A = list( map( int, input().split())) Q = 10**9 + 7 fact = [1]*(N+1) invs = getInv(N) accI = [0]*(N+1) for i in range(N): fact[i+1] = fact[i]*(i+1)%Q accI[i+1] = (accI[i]+invs[i+1])%Q factN = fact[-1] ans = 0 for i in range(N): C = factN*(accI[i+1] + accI[N-i]-1)*(A[i]%Q)%Q ans += C ans %= Q print(ans)