P1980 [NOIP 2013 普及组] 计数问题

数位拆分 / 统计 1 到 n 中某个数字出现次数

一、先回答问题

这题到底在考什么

枚举 1 到 n 的每个数,逐位拆开,当前位等于 x 就把总次数加一。

对象

保留当前待拆的 t、目标数字 x、总计数 c;每次只处理 t 的个位,再丢掉个位。

为什么能这样做

n 最大 10^6,直接枚举约 7 百万次数位检查,足够快。

先避开的坑

这题统计的是所有整数的所有数位,不是统计有多少个数包含 x。

二、互动演示

样例 n=11, x=1

演示进度

课堂要求:每一步都让学生说出当前保留了什么信息,以及下一步为什么不会漏答案。

三、手推结果

把关键过程写成表

整数数位贡献
111
100, 11
111, 12
四、自己选答案

当堂检查

1 到 11 中数字 1 出现几次?
P1980 和 B4497 的共同模板是什么?
五、C++14 参考代码

代码读慢一点

#include <bits/stdc++.h>
using namespace std;

int main() {
    long long n;
    int x;
    cin >> n >> x;

    long long c = 0;
    for (long long i = 1; i <= n; i++) {
        long long t = i;
        do {
            if (t % 10 == x) c++;
            t /= 10;
        } while (t);
    }

    cout << c << "\n";
    return 0;
}

读代码抓这几处

六、收口

复杂度与常见错误

复杂度:时间 O(n * log10 n),空间 O(1)。

源文件:GESP2/P1980.md · GESP2/P1980_solution.md