“聚小而大。”
定义
一种以位数为转移条件的 $dp$ ,一般是统计一个区间内满足一类条件的计数 $dp$ 。一般的初始转移有二维 $dp_{i,j}$ 表示有 $i$ 位且末位为 $j$ 的统计个数。一般满足差分性质(与树状数组类似),即 $[l,r]=[1,r]-[1,l-1]$ 的性质。
写法
迭代式
即使用 for
循环来遍历整个 dp
数组。
1 | inline int dp(int x) |
记忆化
使用dfs
遍历所有的情况
1 | ll dfs(int x/*,bool con1,bool con2...bool conn*/) //一些限制条件,x表示位数 |
初始化
将所有应算的都算出来, $dp$ 的过程只是在查找 $limit$ 范围之内的。
1 | inline void init() |
例题
Luogu P2657 windy数
解释
数位 $dp$ 模板题,用 $dp_{i,j}$ 表示位数为 $i$ ,最高位是 $j$ 的计数,递推出在 $limit$ 内满足的个数,对于相邻的两位,只要其相差不到 $2$ 都可以相加。最终答案便是 dp(r)-dp(l-1)
。
AC Code
递推写法。
查看代码
1 |
|
Loj #10166 数字游戏
解释
与上一题差不了多少。预处理 $dp_{i,j,k}$ 表示 $i$ 位最高位为 $j$ 且模 $k$ 的计数即可。
AC Code
同样是迭代式写法。
查看代码
1 |
|
Luogu P6669 组合数问题
解释
其实这道题用记忆化要好些一些,一个五维数组记录位数,$n$ 数是否达到上限, $m$ 数是否达到上限,$n$和 $m$ 是否相同过以及 $n$ 是否小于过 $m$ 的情况。这里需要很多组合数的前置知识(比如卢卡斯定理)以优化。这里不多解释,有兴趣可以在洛谷上看题解。
AC Code
查看代码
1 |
|