题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089
一道数位dp的入门题,数据超级小完全可以用暴力过,当然用记忆化搜索写更好,能练练数位dp
的记忆化搜索的写法。
开始要找dp的设法,首先必要的一维是长度,然后第二维可以存前一个数也可以表示状态,这里
要选择表示状态。如果选择存前一个数这样不好,因为返回的dp要要求不含有不吉利的数字,所
以这里优先考虑dp[len]这些数是否要满足要求,所以第二维要设state表示状态,只返回状态满
足要求的dp值。
#include <iostream> #include <cstring> using namespace std; int n , m , dp[12][3] , dig[12]; int dfs(int len , int state , int flag) { if(len == 0) { return state < 2; } if(!flag && state < 2 && dp[len][state] != -1) { return dp[len][state]; } int t = flag ? dig[len] : 9; int sum = 0; for(int i = 0 ; i <= t ; i++) { if(state == 0) { if(i == 4) { continue; } else { if(i == 6) { sum += dfs(len - 1 , 1 , flag && i == t); } else { sum += dfs(len - 1 , 0 , flag && i == t); } } } if(state == 1) { if(i == 2 || i == 4) continue; else { if(i == 6) { sum += dfs(len - 1 , 1 , flag && i == t); } else { sum += dfs(len - 1 , 0 , flag && i == t); } } } } if(!flag && state < 2) { dp[len][state] = sum; } return sum; } int Gets(int x) { memset(dp , -1 , sizeof(dp)); memset(dig , 0 , sizeof(dig)); int len = 0; if(x == 0) { dig[++len] = 0; } while(x) { dig[++len] = x % 10; x /= 10; } return dfs(len , 0 , 1); } int main() { while(scanf("%d%d" , &n , &m) != EOF) { if(n == 0 && m == 0) { return 0; } printf("%d " , Gets(m) - Gets(n - 1)); } return 0; }