题意:
统计[a, b]或[b, a]中0~9这些数字各出现多少次。
分析:
这道题可以和UVa 11361比较来看。
同样是利用这样一个“模板”,进行区间的分块,加速运算。
因为这里没有前导0,所以分块的时候要多分几种情况。
以2345为例,这是一个四位数,首先要计算一下所有的一位数、两位数以及三位数各个数字出现的个数。
对应的模板分别为n,n*,n**,其中n代表非零数字,*代表任意数字。
考虑这样一个长为l的模板****(l个*),这样的数共10l个,而且各个数字都是等频率出现,所以每个数字出现的次数为l * 10l-1
统计完三位数一下的数字之后,就开始统计四位数字:1***,20**,21**,22**,230*,231*,232*,233*,2340,2341,2342,2343,2344,2345
在统计每个模板时,分这样两块计算:
- **中该数字出现的次数
- 前面该数出现的次数,比如22**,前面两个2会重复102次
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 int pow10[10], cnt[10]; 7 8 int f(int d, int n) 9 { 10 char s[15]; 11 sprintf(s, "%d", n); 12 int len = strlen(s); 13 int ans = 0; 14 15 for(int i = 1; i < len; i++) 16 { 17 if(i == 1) { ans++; continue; } 18 ans += 9 * cnt[i - 1]; 19 if(d > 0) ans += pow10[i - 1]; 20 } 21 22 int pre[10]; 23 for(int i = 0; i < len; i++) 24 { 25 pre[i] = (int)(s[i] - '0' == d); 26 if(i) pre[i] += pre[i - 1]; 27 } 28 29 for(int i = 0; i < len; i++) 30 { 31 int maxd = s[i] - '0' - 1; 32 int mind = 0; 33 if(i == 0 && len > 1) mind = 1; 34 for(int digit = mind; digit <= maxd; digit++) 35 { 36 ans += cnt[len - i - 1]; 37 if(i) ans += pre[i - 1] * pow10[len - i - 1]; 38 if(digit == d) ans += pow10[len - i - 1]; 39 } 40 } 41 return ans; 42 } 43 44 int main() 45 { 46 //freopen("in.txt", "r", stdin); 47 48 pow10[0] = 1; 49 for(int i = 1; i <= 8; i++) 50 { 51 pow10[i] = pow10[i - 1] * 10; 52 cnt[i] = pow10[i - 1] * i; 53 } 54 55 int a, b; 56 while(scanf("%d%d", &a, &b) == 2 && a && b) 57 { 58 if(a > b) swap(a, b); 59 for(int d = 0; d <= 9; d++) 60 { 61 if(d) printf(" "); 62 printf("%d", f(d, b+1) - f(d, a)); 63 } 64 printf(" "); 65 } 66 67 return 0; 68 }