F - substr = S 解説
by
yfuka86
桁DPの要領でまとめて計算することが可能です。
本質的な計算対象や、R以下とL-1以下の場合をそれぞれ計算し差を取るパートは公式解説と同じです。
部分問題において求める\(x\)以下に関する答えを\(f(x)\)とし、これを考えます。
\( dp[i][j][k][l] \) := 上から\(i\) 桁目まで決定している場合の数で、
- \(S\) の \(j\) 文字目まで一致している
- \(i\)桁目まで最大値\((=x)\)と一致している・いない (\(k = {1, 0}\) )
- \(i\)桁目までで0以外の数値が1回以上現れている・いない (\(l = {1, 0}\) )
と定め、\(dp[0][0][1][0] = 1\)と初期化します。
遷移を以下のように定めます。\(d\)を次に決める桁の数とし、\([0, 9]\)で(\(x\)を超えない範囲で)ループを回します。
\(nk := ( k=1かつ dとxのi桁目が一致している: 1, それ以外: 0 )\)
\(nl := (l=1またはdが0でない: 1, それ以外: 0)\)
とすると、
\(j=0\) のとき
\(dp[i + 1][j][nk][nl]\) += \(dp[i][j][k][l] \)\(j\in[0,|S|)\) のとき
\(d\)と\(S\)の\(j+1\)文字目が一致し、\(nl\)が\(1\)である場合のみ
\(dp[i + 1][j + 1][nk][nl]\) += \(dp[i][j][k][l] \)\(j=|S|\)のとき
\(dp[i + 1][j][nk][l]\) += \(dp[i][j][k][l] \)
(\(l=0の場合は0が入っている\))
と場合分けして遷移します。順にSとの一致前、Sとの一致、Sと一致後の数え上げに相当します。
結果、\(f(x) = dp[xの桁数][|S|][0][1] + dp[xの桁数][|S|][1][1] \)となります。
実装例(C++):https://atcoder.jp/contests/abc295/submissions/40103568
P.S. 筆者はkについてxと一致している場合1としていますが、これと逆にxより真に小さいことが確定している場合1とするのがより一般的なようです。
投稿日時:
最終更新: