这题到底在考什么
枚举 1 到 n 的每个数,逐位拆开,当前位等于 x 就把总次数加一。
对象
保留当前待拆的 t、目标数字 x、总计数 c;每次只处理 t 的个位,再丢掉个位。
为什么能这样做
n 最大 10^6,直接枚举约 7 百万次数位检查,足够快。
先避开的坑
这题统计的是所有整数的所有数位,不是统计有多少个数包含 x。
样例 n=11, x=1
演示进度
课堂要求:每一步都让学生说出当前保留了什么信息,以及下一步为什么不会漏答案。
把关键过程写成表
| 整数 | 数位 | 贡献 |
|---|---|---|
| 1 | 1 | 1 |
| 10 | 0, 1 | 1 |
| 11 | 1, 1 | 2 |
当堂检查
1 到 11 中数字 1 出现几次?
P1980 和 B4497 的共同模板是什么?
代码读慢一点
#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;
}
读代码抓这几处
- 外层枚举 1 到 n。
- do-while 是稳妥的数位拆分模板。
- 计数总和用 long long 更稳。
复杂度与常见错误
复杂度:时间 O(n * log10 n),空间 O(1)。
- 把“出现次数”误解为“包含这个数字的整数个数”。
- 只统计个位。
- 总计数变量类型过小。
源文件:GESP2/P1980.md · GESP2/P1980_solution.md