这道题的题解有几个亮点
一个是每次只统计一个数字来简化思维
一个是统计当前位数的时候分三个部分来更新答案
具体看代码,有注释
#include<cstdio>
#include<cstring>
#include<algorithm>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;const int MAXN = 10;
int pow[MAXN], cnt[MAXN];int f(int d, int n) //分单个数字来统计,简化了思维过程
{char s[MAXN];sprintf(s, "%d", n);int len = strlen(s), ans = 0;REP(i, 1, len) //如果是四位数,那么一,二,三位数的数字的个数可以直接统计,以此类推 {if(i == 1) ans++;else{ans += 9 * cnt[i-1];if(d > 0) ans += pow[i-1]; //注意首位要单独出来统计 }}int pre[10]; //前i位数d出现的次数 REP(i, 0, len){pre[i] = s[i] - '0' == d ? 1 : 0;if(i > 0) pre[i] += pre[i-1];}REP(i, 0, len){int maxd = s[i] - '0';int mind = (i == 0 && len > 1); //首位不为0,只有0除外 REP(digit, mind, maxd) {ans += cnt[len-i-1]; //当前位数的后面的数 if(i > 0) ans += pre[i-1] * pow[len-i-1]; //当前位数的前面的数 if(digit == d) ans += pow[len-i-1]; //当前位数 }}return ans;
}int main()
{pow[0] = 1;REP(i, 1, 9){pow[i] = pow[i-1] * 10; //10的i次方 cnt[i] = pow[i-1] * i; //i位数中每个数字出现的次数(0可以为首位) }int a, b;while(~scanf("%d%d", &a, &b) && a){if(a > b) swap(a, b);REP(d, 0, 10){if(d) printf(" ");printf("%d", f(d, b + 1) - f(d, a));} puts("");}return 0;
}