给你一个区间[a, b]  (0 < a, b < ),让你求出区间内[0~9]每个数字出现的总次数

思想:

实现一个count(n, x)代表1~n中x出现的次数
然后用前缀和解决[a,b]中x出现的次数即

ans = count(b, x) - count(a, x);

对于一个数n,形式为abcdefg

找1~abcdefg中,1在d位上出现的次数即有两种情况待讨论

设我们讨论的数为x = 1

1.首数为000~abc-1, 那么efg可取000~999,共abc*999种

2.首数为abc,

2.1若x > d,共0种

2.2若x == d,那么efg可取000~efg,共efg + 1种

2.3若x < d, 那么efg可取000~999, 共1000种

 

对于x = 0的特殊情况,我们需要特殊讨论。

(1)x不能位于最高位,即不能出现前导零

(2)x位于非最高位时,首数为001~abc - 1的情况,和首数为abc的情况。

 

代码如下(主要就是细节的实现较为麻烦)

#include<cstdio>
#include<iostream>

using namespace std; 

int get(int num[], int en, int fir){
	
	int ans = 0;
	for(int i = en; i >= fir; i--){
		ans = ans * 10 + num[i];
	}
	return ans;
}

int power10(int i){
	int ans = 1;
	while(i--){
		ans *= 10;
	}
	return ans;
}

int count(int n, int x){
	int num[10];
	
	int g = 0;
	while(n){
		num[g++] = n % 10;
		n /= 10;	
	}
	//逆序存储,即12345存储到num[]中是5,4,3,2,1 
	
	int res = 0;
	
	//从最高位开始遍历 
	if(x){ 
		for(int i = g - 1; i >= 0; i--){
			
			//000~abc - 1,由于最高位前没有位了,所以这步从次高位开始 
			if(i < g - 1){
				res += get(num, g - 1, i + 1) * power10(i);
				//get得到了当前遍历位的前方数的大小,即 
				//power10得到了当前遍历位后的数的10的位数次方 
				
				
			}
			
			//abc
			if(num[i] == x) res += get(num, i - 1, 0) + 1;
			else if(num[i] > x) res += power10(i);
		}
	}
	
	else{
		
		for(int i = g - 1 - 1; i >= 0; i--){
			if(i < g - 1){
				//当你遍历到当前位时,当前这位的前面之和是不能为0的 
				res += (get(num, g - 1, i + 1) - 1) * power10(i);
			}
			if(num[i] == x) res += get(num, i - 1, 0) + 1;
			else if(num[i] > x) res += power10(i);
		}
	}
	return res;
}

int main()
{
	int l, r;
	while(~scanf("%d%d", &l, &r), l || r){ 
		if(l > r) swap(l, r);
		
		for(int i = 0; i <= 9; i++)
			printf("%d ", count(r, i) - count(l - 1, i));
	} 
	return 0;
}