给你一个区间[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;
}