题目大意:
给定a,b, 求 [a, b] 中所有整数中, 每个数字出现的次数。
输入格式:
输入两个整数 a 和 b。
输出格式:
输出 10 个整数, 分别表示 0, 1, 2, ....., 9 在 [a, b] 中出现了多少次。
样例:
输入:
1 99
输出:
9 20 20 20 20 20 20 20 20 20
数据范围:
- 对于 30% 的数据,保证 a ≤ b ≤ 10^6;
- 对于 100% 的数据,保证 1 ≤ a ≤ b ≤ 10^12。
做法:
通过观察数据范围发现 a, b 非常大, 直接O(n)枚举会寄, 于是我们另辟蹊径, 可以发现求区间[a, b] 中所有整数, 每个数字出现的次数。 相当于求 [0, b] 每个数字出现的次数 减去 [0, a - 1] 每个数字出现的次数。
于是问题变成了求[0, b] 和 [0, a - 1] 中所有整数, 每个数字出现的次数。(跟没变一样。。。)
但这样还是会TLE啊。
再进一步想,求每个数字出现的次数就是统计每一位上每一个数字出现的次数
于是问题转换成枚举每一位然后统计。
那么我们来看一个栗子:1923
数字:1 9 2 3
下标:4 3 2 1
当我们统计位置 2 上每一个数字出现的个数是可以分两种情况考虑:
1.因为我们构造的数必须在 [0, 1923] 之中,所以当位置 2 前面的那一部分(即:位置3, 4)小于 1923 的前面那一部分(即:位置3, 4) 那么位置 2 可以填 0 到 9 中的任意一个数。那么每个数有多少个呢? 因为 1923 前面那一部分是 "19",我们构造的数要小于 "19" 那么只能填 0 到 18, 同时我们保证了前面一定小于 19 所以位置 2 后面的那一部分每一位都可以填0到9, 那么其总数就是 19 * 10^1
2.上一种情况我们只考虑了小于 1923 的数,这里我们还是针对位置 2 考虑前面那一部分(即:位置3, 4)等于 19 的情况, 可以发现对于位置2,可以填 0 到 2 中的所有数,不过这里注意 对于 0 到 1 后面每一位都可以填 0 到 9, 但是对于 2 我们后面只能填 0 到 3(不能超过1923)
那么对于数字 0 到 1 其总数就是 10^1
对于数字 2 其总数就是 4 (3 + 1)
总结下就是对于数字 xnx(n-1)x(n-2)...x1 指的是 x3 = 1, x2 = 2, x1 = 3 组成的数 123
1.位置 i 上 f[0...9] += xnx(n-1)x(n-2)...x(i+1) * 10^i-1
2.位置 i 上 f[0...xi - 1] += 10^i-1, f[xi] += x(i-1)x(i-2)...x1
注意:因为 0 前面不能为 0, 所以得注意一下(可以像我一样单独考虑0)
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
int g[20], f[20];
int fast_pow(int a, int b){
int res = 1;
while(b){
if(b & 1) res *= a;
a *= a;
b >>= 1;
}
return res;
}
signed main() {
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
int a, b, alen = 0, blen = 0, a1, b1;
cin >> a >> b;
a1 = max(0ll, a - 1), b1 = b;
while(a1){
a1 /= 10;
alen++;
}
while(b1){
b1 /= 10;
blen++;
}
int op = a;
a = max(a - 1, 0ll);
for(int i = 1; i <= alen; i++){//
if(i < alen){
for(int j = 1; j <= 9; j++){
g[j] = g[j] + (a / fast_pow(10, i)) * fast_pow(10, i - 1);
}
}
for(int j = 1; j <= (a / fast_pow(10, i - 1)) % 10; j++){
if(j == ((a / fast_pow(10, i - 1)) % 10)) g[j] = g[j] + a - ((a / fast_pow(10, i - 1)) * fast_pow(10, i - 1)) + 1;
else g[j] = g[j] + fast_pow(10, i - 1);
}
}
for(int i = 1; i <= alen; i++){
if(i < alen){
g[0] = g[0] + (a / fast_pow(10, i) - 1) * fast_pow(10, i - 1);
}
if((a / fast_pow(10, i)) > 0){
if(((a / fast_pow(10, i - 1)) % 10) == 0) g[0] = g[0] + a - ((a / fast_pow(10, i - 1)) * fast_pow(10, i - 1)) + 1;
else g[0] = g[0] + fast_pow(10, i - 1);
}
}
a = op;
for(int i = 1; i <= blen; i++){
if(i < blen){
for(int j = 1; j <= 9; j++){
f[j] = f[j] + (b / fast_pow(10, i)) * fast_pow(10, i - 1);
}
}
for(int j = 1; j <= (b / fast_pow(10, i - 1)) % 10; j++){
if(j == (b / fast_pow(10, i - 1)) % 10) f[j] = f[j] + b - ((b / fast_pow(10, i - 1)) * fast_pow(10, i - 1)) + 1;
else f[j] = f[j] + fast_pow(10, i - 1);
}
}
for(int i = 1; i <= blen; i++){
if(i < blen){
f[0] = f[0] + (b / fast_pow(10, i) - 1) * fast_pow(10, i - 1);
}
if((b / fast_pow(10, i)) > 0){
if(((b / fast_pow(10, i - 1)) % 10) == 0) f[0] = f[0] + b - ((b / fast_pow(10, i - 1)) * fast_pow(10, i - 1)) + 1;
else f[0] = f[0] + fast_pow(10, i - 1);
}
}
for(int i = 0; i <= 9; i++){
cout << f[i] - g[i] << " ";
}
return 0;
}//by hwl