码迷,mamicode.com
首页 > 其他好文 > 详细

「 HDOJ P3555 」 Bomb

时间:2018-09-09 22:15:45      阅读:233      评论:0      收藏:0      [点我收藏+]

标签:记忆   stream   pac   证明   mes   hdoj   也有   main   class   

# 题目大意

给出 $\text{T}$ 个数,求 $[1,n]$ 中含 ‘49’ 的数的个数。

 

# 解题思路

求出不含 ‘49‘ 的数的个数,用总数减去就是答案。

数位 $DP$,用记忆化来做。

设 $dp[i][0]$ 表示 (这里按照从左往右数) 长度为 $i$ 并且最后一位不是 ‘4‘ 的数的个数。

设 $dp[i][1]$ 表示长度为 $i$ 并且最后一位是 ‘4‘ 的数的个数。

上面这两行看不懂可以先跳过去,是不是很神奇。

这样单说不好说。借助代码来说。具体的看代码里的注释。

 

# 放上代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long LL;
LL T, n, num[30], cnt, dp[30][2];
inline void span(LL x) {            //将数字张开分成一位一位
    cnt = 0;
    while (x != 0) {
        num[++cnt] = x % 10;
        x /= 10;
    }                                //cnt就是长度
}
inline LL dfs(int l, bool flag, bool limit) {            //枚举到了第l位,最高位是cnt
    //flag表示前一位是否是4,limit表示枚举第l位是否存在限制
    if(l == 0) return 1;
    if(!limit && dp[l][flag]) return dp[l][flag];
    //这里返回的原因是没有限制,所以这是一个通用的答案
    LL ans = 0, mx = (limit ? num[l] : 9);
    //这里这个mx是最大能枚举到几,如果这一位存在限制。
    for(int i=0; i<=mx; i++) {
        if(flag && i == 9)                                //判断是否含有‘49’
            continue;
        ans += dfs(l-1, i == 4, i == mx && limit);
        //如果这一位有限制并且现在枚举到的数正好达到最高限制,证明下一位也有限制
    }
    return limit ? ans : dp[l][flag] = ans;
    //如果没有限制就可以将这个通用的答案记录下来
}
int main() {
    scanf("%lld", &T);
    while (T--) {
        memset(num, 0, sizeof(num));
        //这里记得要重置
        scanf("%lld", &n);
        span(n);
        printf("%lld\n", n-(dfs(cnt, false, true)-1));
        //这里为什么要-1?
        //因为在上面的函数中找到的不含‘49’的数包括‘0’,但是最后统计的时候是不包括‘0’的
    }
}

 

「 HDOJ P3555 」 Bomb

标签:记忆   stream   pac   证明   mes   hdoj   也有   main   class   

原文地址:https://www.cnblogs.com/bljfy/p/9615108.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!