问题描述
把前n(n≤10000)个整数顺次写在一起:
123456789101112…数一数0~9各出现多少次
(输出10个整数,分别是0,1,…,9出现的次数)
大神分析
因为 n 的最大值比较小,可以用建表的方式来计算。令 C[n][k] 表示前 n 个数字写在一起,k(k = 0 ~ 9)总共出现了几次,则有 C[n+1][k] = C[n][k] + x 。
其中 x 是 k 在 n + 1 中出现的次数。
直接按照这个公式就可以把所有答案提前计算出来,然后每读入一个 n 就直接输出预处理的结果即可。
代码&注释
#include <iostream>
using namespace std;
const int MAXN = 1e4 + 1;
int C[MAXN][10] = {0};
int main() {
// 预处理部分
for(int i = 1; i < MAXN; i++) {
// 由公式 C[i][k] = C[i - 1][k] + x
// 可以先把已经计算过的 C[i - 1][k] 的值直接赋给 C[i][k],
// 剩下的 x 部分,再单独计算
for(int k = 0; k < 10; k++) {
C[i][k] = C[i - 1][k];
}
// 单独计算公式中的 x
int n = i;
while(n) {
++C[i][n % 10];
n /= 10;
}
}
int T, n;
// 输入实例数目
cin >> T;
while(T--) {
cin >> n;
for(int i = 0; i < 10; i++) {
// 输出的第一项前边,即输出统计的 0 的结果时,前面不输出空格
if(i) cout << " ";
// 第一项的前面没有空格,后面的项都是前面有空格的
cout << C[n][i];
}
cout << endl;
}
return 0;
}
启发
理解题意很重要,建表的方法很难想,第一次吗?好像前面好多道题头用到了建表,预处理之类的手法。