这道题的题解有几个亮点
一个是每次只统计一个数字来简化思维
一个是统计当前位数的时候分三个部分来更新答案
具体看代码,有注释
#include#include #include #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;}