Branched Evolution

Competitive Programming in Python

ABC 135 D - Digits Parade

問題

$0$ ~ $9$ または $?$ からなる文字列 $S$ の $?$ を数字に置き換えてできる整数のうち $13$ で割って $5$ あまる数の個数を求めよ。

atcoder.jp

解説

上から $i - 1$, $i$ 桁を $13$ で割った余りをそれぞれ $r$, $k$ とすると、$\mathrm{mod}\ 13$ において $10$ の逆元が$4$ なので $$ \begin{aligned} 10 r + k &= j \\ r &= 4(j - k) \end{aligned} $$ よって、$S[i - 1] = k$ の場合は、上から $i$ 桁について $13$ で割って $j$ あまる個数は上から $i - 1$ 桁について $13$ で割って $4(j - k)$ あまる個数に等しい。
一方、$S[i - 1] = \ ?$ の場合は $k = 0$ から $9$ までの和になる。
$DP[i][j]$ を上から $i$ 桁について $13$ で割って $j$ あまる個数とすると、遷移式は $$ DP[i][j]= \begin{cases} DP[i-1][4(j - k)] \ \ (S[i - 1] = k) \\ \sum_{k = 0}^{9}DP[i-1][4(j - k)] \ \ (S[i - 1] = \ ?) \end{cases} $$

実装

S = input()
n = len(S)
p = 10**9+7
DP = [[0]*13 for i in range(n+1)]
DP[0][0] = 1
for i in range(1, n+1):
    for j in range(13):
        if S[i-1] == '?':
            DP[i][j] = sum([DP[i-1][(4*(j-k)) % 13] for k in range(10)]) % p
        else:
            k = int(S[i-1])
            DP[i][j] = DP[i-1][(4*(j-k)) % 13]
print(DP[n][5])

atcoder.jp