数位动态规划是求解一个大区间[L, R]中间满足条件Q的所有数字的个数(或者和,或其他)的一种方法。它通过分析每一位上的数字,一般用 dp[len][digit][...] 来表示状态“len位长的数字,最高位数字为digit所具有的xx特性”,利用记忆化搜索保存中间结果,从而加快求解速度。
通过求 f(n) 从0到n中满足条件Q的数字的个数,则所求的结果为 f(R) - f(L-1).
参考于:here
大多数数位dp都可以用一个DFS函数来进行记忆化搜索:
#include <bits/stdc++.h> using namespace std; #define BITNUM 10 #define MAXN 10 int dp[BITNUM][MAXN]; int bits[BITNUM]; ///pos为当前位,digit标记状态的值(注意压缩抽象),limit 表示digit是否是第len位(从低位向高位数,个位为第1位)的范围边界 int dfs(int pos, int digit, bool end_flag) { if(!end_flag && dp[pos][digit] != -1)///记忆化搜索,如果之前已经求出来了,则返回。注意这里要求 end_flag为false return dp[pos][digit]; if(pos==0) return dp[pos][digit]=1; int end = end_flag ? bits[pos-1] : 9 ;///如果当前位是边界数字N对应位的最大值,则下一位的范围只能从0到边界数字N的下一位的最大值。否则为0 到 9 int ans = 0; for(int i = 0; i <= end; i++) { if(!(digit==6&&i==2) && i!=4) ans += dfs(pos - 1, i, end_flag && (i==end)); } if (!end_flag) ///digit不是第len位的最高范围,则可以将结果缓存 dp[pos][digit] = ans; return ans; } int solve(int x) { memset(bits,0,sizeof bits); int pos=0; while(x) { bits[pos++]=x%10; x/=10; } return dfs(pos, bits[pos], 1);///为方便当前为设置为0 } int main() { memset(dp,-1,sizeof dp); int m,n; while(~scanf("%d%d",&m,&n)&&(m||n)) { int x1=solve(m-1); int x2=solve(n); printf("%d\n",x2-x1); } return 0; }