1.题目描述:点击打开链接
2.解题思路:本题要求数从a到b这串数字中0~9这10个数的个数。这类问题的一般步骤都是先用f(n,d)计算出0~n中d数字出现的次数,那么答案就是f(b,d)-f(a-1,d)。计算f(n)函数时,可以考虑递推法计算,下面举例解释计算过程:
比如1~2974这个序列,将它拆成1~2970和2971~2974两部分,后者就是个位从1到4,这4个数字先各出现一次,然后2,9,7这3个数字分别出现了5次(虽然是从2971开始,但2970也要算上);前者的数位统计利用递推来解决,先只统计2969个位的这10个数出现的全部次数(从0数起),每个数都出现了297次。然后只用重复上述步骤,计算296这个数即可,但这时就相当于10个数地计算了。即每次向下一层计算时,乘子m要乘以10。归纳起来其实就是找f(k)和f(10*k+m)之间的关系。
3.代码:
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<algorithm> #include<string> #include<sstream> #include<set> #include<vector> #include<stack> #include<map> #include<queue> #include<deque> #include<cstdlib> #include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<functional> using namespace std; #define N 10+5 int a[N], b[N]; void copy(int*a, int*b) { for (int i = 0; i < 10; i++) { a[i] = b[i]; b[i] = 0; } } void calculate(int n, int m)//m是乘子,每次进入下一层自乘10 { int x = n / 10;//不含末位的部分 int y = n % 10;//末位 int temp = x; for (int i = 1; i <= y; i++)//先数一数从10*x+1到10*x+y这段序列中不超过个位数的数的个数 b[i] += m; for (int i = 0; i < 10; i++)//计算10*x-10到10*x-1这段序列中个位数的总个数 b[i] += m*x; while (temp) { b[temp % 10] += m*(y + 1);//再数一数从10*x+0到10*x+y这段序列中非个位数的数的个数,注意不要算成10*x+1到10*x+y了 temp /= 10; } if (x) calculate(x - 1, m * 10);//递归解决 } int main() { //freopen("test.txt", "r", stdin); int aa,bb; while (cin >> aa >> bb,aa||bb) { if (aa > bb)swap(aa, bb); memset(b, 0, sizeof(b)); calculate(aa - 1, 1); copy(a, b); calculate(bb, 1); for (int i = 0; i < 10; i++) printf("%d%c", b[i] - a[i], i == 9 ? '\n' : ' '); } return 0; }