数位dp模版(dp)

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 
 6 using namespace std;
 7 
 8 int t;
 9 long long dp[19][19][2005];
10 long long l, r;
11 int shu[20];
12 
13 long long dfs(int len,..., bool shangxian)
14 {
15     if (len == 0)
16         return ...;
17     if (!shangxian && dp[len][...])
18         return dp[len][...];  //dp数组的内容应和dfs调用参数的内容相同,除了是否达到上限
19     long long cnt = 0;
20     int maxx = (shangxian ? shu[len] : 9);
21     for (int i = 0; i <= maxx; i++)
22     {
23         ...;
24         cnt += dfs(len - 1,..., shangxian && i == maxx);
25     }
26     if (!shangxian)
27         dp[len][...] = cnt;
28     return cnt;
29 }
30 
31 long long solve(long long x)
32 {
33     int k = 0;
34     while (x)
35     {
36         shu[++k] = x % 10;
37         x /= 10;
38     }
39     return dfs(k,...,1)
40 }
41 
42 int main()
43 {
44         memset(dp, 0, sizeof(dp));
45         scanf("%lld%lld", &l, &r);   //有些题目其实并不需要用到long long
46         printf("%lld
", solve(r) - solve(l - 1)); //只有满足区间减法才能用
47 
48     //while (1);
49     return 0;
50 }
View Code

数位dp是一种计数用的dp,一般就是统计一个区间[l,r]内满足一些条件数 的个数,所谓数位dp,字面意思就是在数位上dp。数位的含义:一个数有个位,十位,百位,千位···数的每一位就是数位。

之所以要引入数位的概念完全就是为了dp。数位dp的实质就是换一种暴力枚举的方式,使新的枚举方式满足dp的性质,然后记忆化即可。

两种不同的枚举:对于一个求区间[l,r]满足条件数的个数,最简单的暴力如下:

for(int i=l;i<=r;i++)
           if(right(i))
                  ans++;

  然而这样枚举不方便记忆化,或者根本无状态可言。

原文地址:https://www.cnblogs.com/Roni-i/p/7307765.html