数位DP
什么是数位DP
数位DP是DP的一种,顾名思义,按每一个数位来进行DP。
什么时候使用
题目的要求与一个数字相关,并且它能通过每一个数位来进行转移。
例题:求所有
n
n
n位数中能被
m
m
m整除的数的个数。
怎么使用
一般的DP是多维的,首先会有一维表示的是当前到了第几位,通常情况这一维可以使用滚动。
其它的就是根据题目的实际要求了,如例题就需要一维来记录除以
m
m
m的余数。
以例题为例,我们来讲讲数位DP怎么实现。
状态与转移
我们设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示当前到了第
i
i
i位,除以
m
m
m的余数为
j
j
j的方案数。
一般是从高位往低位DP,因为最高位不能为
0
0
0,所以我们对
i
=
1
i=1
i=1的情况先处理好:
f
[
1
]
[
i
m
o
d
  
m
]
=
1
(
1
≤
i
≤
9
)
f[1][i\mod m]=1(1≤i≤9)
f[1][imodm]=1(1≤i≤9)
接着我们用第
i
i
i位的状态去更新第
i
+
1
i+1
i+1位的状态,每次枚举当前在第
i
+
1
i+1
i+1位加入
k
k
k。
想想怎么转移?
对于当前的余数
j
j
j,在末尾加入了
k
k
k,余数变成什么?
根据同余的性质,我们自然可以得到:余数变成了
(
j
∗
10
+
k
)
m
o
d
  
m
(j*10+k)\mod m
(j∗10+k)modm。
所以,状态转移方程如下:
f [ i + 1 ] [ ( j ∗ 10 + k ) m o d    m ] + = f [ i ] [ j ] ( 1 ≤ i < n , 0 ≤ j < m , 0 ≤ k ≤ 9 ) f[i+1][(j*10+k)\mod m]+=f[i][j](1≤i<n,0≤j<m,0≤k≤9) f[i+1][(j∗10+k)modm]+=f[i][j](1≤i<n,0≤j<m,0≤k≤9)
最后的答案是什么?
首先,第一维自然是
n
n
n,那么第二维取什么值呢?
显而易见,要求是
m
m
m的倍数,所以第二维是
0
0
0。
综上所述,最后的答案是
f
[
n
]
[
0
]
f[n][0]
f[n][0]。