数位DP的问法是从某个数到某个数的区间里,求出满足题目要求的个数;
如本题所说的不要62和4,就是求出这个区间内,满足这一条件的数;
比如问 6 199的这个区间内满足条件的数,那么就求出1到199满足的数减去1到(6-1)满足的数即可;
那么 具体怎么从操作呢?
首先,我们先求出这个数的a[]数组,求出每一位具体是什么数(dfs的时候需要用到)
然后开始dfs,从最高位开始逐步深搜下来,将不满足的情况过滤掉,然后将满足普遍情况的值保存下来
那么哪些是普遍情况呢:就是无论不会被限制条件限制掉的状态的数
最后枚举到最低位-1,再层层回溯就好了,
本题中的体现形式是:!limit
1 #include<cstdio> 2 #include<string.h> 3 using namespace std; 4 const int maxn=10; 5 int dp[maxn][2],a[maxn]; 6 int dfs(int pos,int pre,int sta,bool limit) 7 { 8 if(pos==-1) return 1; //枚举到比最低为少一位的时候,就开始回溯 9 if(!limit&&dp[pos][sta]!=-1) return dp[pos][sta]; //满足普遍情况的就可以直接用 10 //这是十分必要的,没有这一步的话跟普通dfs没什么区别 11 int up=limit?a[pos]:9; //保存这个数的每一位的作用就体现在这里了 12 //假如这一位数是5,那么他枚举的数便不能超过这个数 13 int tmp=0; 14 for(int i=0;i<=up;i++){ 15 if(i==4) continue; 16 if(pre==6&&i==2) continue; //不满足的情况就过滤; 17 tmp+=dfs(pos-1,i,i==6,limit&&i==a[pos]); 18 } 19 if(!limit) dp[pos][sta]=tmp; //满足普遍情况就保存; 20 return tmp; 21 } 22 int solve(int n) 23 { 24 int pos=0; 25 while(n){ 26 a[pos++]=n%10; //将这个数每一位的数保存下来; 27 n/=10; 28 } 29 return dfs(pos-1,-1,0,true); 30 } 31 int main() 32 { 33 int n,m; 34 memset(dp,-1,sizeof(dp)); 35 while(scanf("%d%d",&n,&m)!=EOF){ 36 if(m==0&&n==0) break; 37 printf("%d\n",solve(m)-solve(n-1)); 38 } 39 return 0; 40 }