🚧 This website is under construction. 🚧
AtCoder
ABC
183
E

DP
累積和
E
ABC

ABC183 E - Gueen on Grid

https://atcoder.jp/contests/abc183/tasks/abc183_e (opens in a new tab)

水色下位。

累積和で DP の遷移を高速化するタイプの問題。

右、下、右下と 3 方向への遷移が考えられるため、3 つの累積和テーブルを個別に用意しておく必要があるというのは分かるが、累積和テーブルの遷移が難しい。

公式解説では、累積和[i] = 元配列[i-1] + 累積和[i-1]のようなことをしているが、これでは累積和[i]は実際には配列[0] ~ 配列[i-1]の和を求めていることになる。

なにか気持ち悪いが、確かにitertools.accumulate(array, initial=0)とした時も意味的には同じになるのか別に問題ないかとも思った。

**追記:**遷移時に必要なのは直前までの累積和なのでこれでいい。

MOD = 10**9 + 7
 
h, w = map(int, input().split())
s = [input() for _ in range(h)]
 
dp = [[0 for _ in range(w)] for _ in range(h)]
 
acc_right = [[0 for _ in range(w)] for _ in range(h)]
acc_bottom = [[0 for _ in range(w)] for _ in range(h)]
acc_diag = [[0 for _ in range(w)] for _ in range(h)]
 
dp[0][0] = 1
 
for i in range(h):
    for j in range(w):
        if s[i][j] == "#":
            continue
        # 右
        if j - 1 >= 0:
            acc_right[i][j] = dp[i][j - 1] + acc_right[i][j - 1]
            dp[i][j] += acc_right[i][j]
        # 下
        if i - 1 >= 0:
            acc_bottom[i][j] = dp[i - 1][j] + acc_bottom[i - 1][j]
            dp[i][j] += acc_bottom[i][j]
        # 右下
        if j - 1 >= 0 and i - 1 >= 0:
            acc_diag[i][j] = dp[i - 1][j - 1] + acc_diag[i - 1][j - 1]
            dp[i][j] += acc_diag[i][j]
 
        acc_right[i][j] %= MOD
        acc_bottom[i][j] %= MOD
        acc_diag[i][j] %= MOD
        dp[i][j] %= MOD
 
if not __debug__:
    print(*dp, sep="\n")
 
print(dp[h - 1][w - 1])