1 条题解

  • 0
    @ 2025-6-16 16:39:45
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define LL long long  // 修改为long long类型
    
    LL dp[15][15][2]; // dp[pos][pre_zero][limit]
    int digit[15];
    
    // 记忆化搜索数位DP
    LL dfs(int pos, int pre_zero, int limit) {
        if (pos == -1) return 0; // 前导零不计数
        if (!limit && !pre_zero && dp[pos][0][0] != -1) 
            return dp[pos][0][0];
        if (!limit && pre_zero && dp[pos][1][0] != -1) 
            return dp[pos][1][0];
        
        int up = limit ? digit[pos] : 9;
        LL res = 0;
        
        for (int i = 0; i <= up; i++) {
            int new_limit = limit && (i == up);
            int new_pre_zero = pre_zero && (i == 0);
            
            if (new_pre_zero) {
                res += dfs(pos - 1, new_pre_zero, new_limit);
            } else {
                res += dfs(pos - 1, new_pre_zero, new_limit);
                if (i == 0) res += 1; // 当前位是0则计数
            }
        }
        
        if (!limit) {
            if (pre_zero) dp[pos][1][0] = res;
            else dp[pos][0][0] = res;
        }
        return res;
    }
    
    // 计算0到x中0的个数
    LL solve(LL x) {
        if (x < 0) return 0;
        int pos = 0;
        while (x) {
            digit[pos++] = x % 10;
            x /= 10;
        }
        memset(dp, -1, sizeof(dp));
        return dfs(pos - 1, 1, 1);
    }
    
    int main() {
        LL m, n;
        while (scanf("%lld %lld", &m, &n) != EOF) { // 修改输入格式说明符
            if (m == -1 && n == -1) break;
            LL ans = solve(n) - solve(m - 1);
            printf("%lld\n", ans); // 修改输出格式说明符
        }
        return 0;
    }
    

    这个问题要求计算从 m 到 n 所有自然数中数字 0 出现的总次数。这是一个典型的数位统计问题,我们可以使用数位动态规划(数位 DP)来高效解决。 解题思路 解决这个问题的核心思路是:

    先计算从 0 到 n 中 0 的个数 再计算从 0 到 m-1 中 0 的个数 两者的差值就是从 m 到 n 中 0 的个数

    • 1

    信息

    ID
    2287
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者