数位dp
含有一个数字(4)或者一个数(62)
对于找这些问题就是:首先dp[]的一维就是这个数的位数,1类问题本质就是在寻找某个状态,所以需要加上状态一维,此时dp[][] 就存在了二维, 数位dp实质就是暴力,因为一般的数位dp是借助dfs的搜索方式来完成的,dfs的工作就是像一颗只有主干和根的树,从主干直接去往根部走,先按照一个根以及这个根的一个分支往下走。遇到符合情况的就改变此时的状态,直到pos<0时,dfs完成了一种情况的搜索, 然后记录结果,继续往下一个分支走,当所有的分支遍历过后,工作完成
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <cstring> 5 #include <algorithm> 6 #include <queue> 7 #include <map> 8 #include <set> 9 #define ll long long 10 using namespace std; 11 const int maxn = 1e5; 12 ll num[20];///直接找数据范围就行 13 ll dp[20][3];///一维代表位数,二维代表状态 14 ll dfs(int pos,int state,int limt) 15 { 16 if(pos < 0)///搜索完所有的位数时返回 17 return state == 2; 18 if(!limt && dp[pos][state]!=-1)///记忆化搜索的返回条件,大量节省时间,没有这一步记忆化就起不上作用了 19 return dp[pos][state]; 20 int up = limt?num[pos]:9;/// up 在这一位上的最大值 21 ll ans=0; 22 for(int i=0; i<=up; i++) 23 { 24 if(i == 4 || state == 2 || i==2 && state == 1) 25 ans += dfs(pos-1, 2, i==up&&limt); 26 else if(i==6) 27 ans += dfs(pos-1, 1, i==up&&limt); 28 else 29 ans += dfs(pos-1, 0, i==up&&limt); 30 ///关于i==up&&limt这一步的理解,现在的条件是不是满足这个式子,yes or no?1:0; 31 32 ///和上面判断条件一样,形式不一样,意思一样 33 /**if(i == 4 || state == 2 || i==2 && state == 1) 34 state2 = 2;///这个状态是重新定义的,不能在state上面直接改,否则后面的for循环的state状态就不符合原来的状态了 35 else if(i==6) 36 state2 = 1; 37 else 38 state2 = 0; 39 ans += dfs(pos-1, state2, i==up&&limt);*/ 40 } 41 ///记忆化需要先记忆,在调用,这里就是 42 if(!limt)///没达到最大值时,调用,因为每个情况的最大值不同,最大值处的值不存在记录意义 43 dp[pos][state] = ans; 44 return ans; 45 } 46 47 ll Solve(ll as) 48 { 49 int len = 0; 50 memset(dp, -1, sizeof(dp)); 51 memset(num, -1, sizeof(num)); 52 while(as) 53 { 54 num[len++] = as%10; 55 as /= 10; 56 } 57 return dfs(len-1, 0, 1);///***** 58 } 59 60 int main() 61 { 62 ll n, m; 63 while(scanf("%lld %lld", &n, &m),n+m) 64 { 65 ll ans = Solve(m) - Solve(n-1); 66 cout<<m - n + 1 - ans<<endl; 67 } 68 return 0; 69 }