目录
- 数位dp学习笔记
- 引入
- 练习题目
- LG2567
- ZJOI2010
- LG3413
- 后记
数位dp学习笔记
在解决一类数位问题的时候,我们发现有些状态是多余的(比如中间的某些数),完全可以合并一起计数,这就是数位dp
具体地说,按每一位进行dp,枚举长度和与要用到的数字
引入
一道例题:求n位数中能被m整除的个数
定义一个状态:\(f[i][j]\)表示当前是第\(i\)位,除以\(m\)的余数为\(j\)
初始情况:\(f[1][i]=1(1\leq i \leq 9)\)
对于下一位\(k\),余数变成\(j*10+k \pmod m\)
转移就是\(f[i+1][(j*10+k) \pmod m]+=f[i][j]\)
由于最后要求倍数,答案为\(f[n][0]\)
练习题目
LG2567
求[L,R]中不含前导零且相邻两个数字之差至少为2的正整数
考虑求出前缀和
由于前导0比较,我们从低往高进行dp
设计状态:\(f[i][j]\)表示\(i\)位数,最高位为\(j\)的windy数个数
预处理出来之后分成三部分计算答案:
- 位数都小于此数
- 位数等于此数,但是最高位小于此数(前导0,不能和3合并)
- 位数等于次数,最高位也相等,考虑枚举有多少位相等
其实有前导0的都可以这样搞计数,只是预处理方法不同
ZJOI2010
\(f[i][j]\)表示\(i\)位数,最高位为\(j\)的windy数个数
\(f[i][j][k]\)表示\(i\)位数,最高位为\(j\)的\(k\)的个数
\(f[i+1][l][k]+=f[i][j][k]+[l=k]\)
统计答案就跟上面一样
LG3413
考虑长度大于等于三的回文子串一定包含长度为2或3的回文子串
所以只需要记录上两个选的数是什么就好了
初始状态,显然处理两位数的,如果两位相等则为1,不相等为0
后记
感觉都能一眼看出数位dp,也挺好推,主要是细节
所以不打算专门做这类题,考场上推一推就好了,细节处理就平时练其他题的时候锻炼一下