HDU 3555 Bomb (数位dp)
题意:求【1,n】当中包含49的一共有多少个数字?
思路:用dp[i][0]来表示 数字位数小于等于i并且不包含49的数字个数,之所以说小于等于而不是严格等于因为有可能有前导零。
dp[i][1]表示 数字位数等于i 并且开头为9,不含“49” 的个数。
dp[i][2] 表示数字位数小于等于i并且包含“49”的个数
初始化完成之后,那么计算给定的n,统计的时候就是对于n的每一位(从高到低)
假设当前是第i位(最右边为第1位),那么这一位的贡献肯定有 dp[i - 1][2] * digit[i];再者,如果这一位大于4的话,那么一定可以贡献出来一个4对应后面的9开头的 从而组成符合条件的数,所以再加上dp[i - 1][1], 如果前面有49了,那么后面的一定是加起来所有的就是(dp[i - 1][2] + dp[i - 1][0]) * digit[i],因为刚开始加过dp[i - 1][2],所以这里直接加dp[i -1][0]就行了。
/************************************************************************* > File Name: bomb.cpp > Author: Howe_Young > Mail: 1013410795@qq.com > Created Time: 2015年09月15日 星期二 18时38分25秒 ************************************************************************/ #include <cstdio> #include <iostream> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 23; ll dp[maxn][3]; //dp[i][0] representation the length less than or equal i not include 49 (may be start with 9, but not include 49) //dp[i][1] representation the length equal i and not include 49 but start with 9 //dp[i][2] representation the length less than or equal i include 49 void init() { dp[0][0] = 1; for (int i = 1; i <= 21; i++) { dp[i][0] = dp[i - 1][0] * 10 - dp[i - 1][1]; dp[i][1] = dp[i - 1][0]; dp[i][2] = dp[i - 1][2] * 10 + dp[i - 1][1]; } } ll get_cnt(ll n) { int digit[maxn], tot = 0; while (n) { digit[++tot] = n % 10; n /= 10; } digit[tot + 1] = 0; ll ans = 0; bool flag = false; for (int i = tot; i >= 1; i--) { ans += digit[i] * dp[i - 1][2]; if (flag) ans += digit[i] * dp[i - 1][0]; else { if (digit[i] > 4) ans += dp[i - 1][1]; if (digit[i + 1] == 4 && digit[i] == 9) flag = true; } } if (flag) ans++; return ans; } int main() { init(); int T; ll n; scanf("%d", &T); while (T--) { cin >> n; cout << get_cnt(n) << endl; } return 0; }