洛谷传送门
BZOJ传送门
题目描述
给定两个正整数 a a a和 b b b,求在 [ a , b ] [a,b] [a,b]中的所有整数中,每个数码( d i g i t digit digit)各出现了多少次。
输入输出格式
输入格式:
输入文件中仅包含一行两个整数 a a a、 b b b,含义如上所述。
输出格式:
输出文件中包含一行 10 10 10个整数,分别表示 0 − 9 0-9 0−9在 [ a , b ] [a,b] [a,b]中出现了多少次。
输入输出样例
输入样例#1:
1 99
输出样例#1:
9 20 20 20 20 20 20 20 20 20
说明
30 % 30\% 30%的数据中, a ≤ b ≤ 1 0 6 a\le b\le 10^6 a≤b≤106;
100 % 100\% 100%的数据中, a ≤ b ≤ 1 0 12 a\le b\le 10^{12} a≤b≤1012。
解题分析
我们一波手推可以发现, 考虑1位的情况下 0 ∼ 9 0\sim 9 0∼9中每个数字出现了一次, 考虑2位的情况下(即把 5 5 5视为 05 05 05) 0 ∼ 99 0\sim 99 0∼99中每个数字出现了 20 20 20次,考虑 3 3 3位的情况下 0 → 999 0\to 999 0→999中每个数字出现了 300 300 300次… 那么我们就可以预处理出这个玩意, 设为 t i m [ i ] tim[i] tim[i]。
考虑 A B C D ABCD ABCD的情况, 首先所有数字作为后三位都出现了 ( A − 1 ) × t i m [ 3 ] (A-1)\times tim[3] (A−1)×tim[3]次, 然后 < A <A <A的数位在第 4 4 4位出现了 1 0 3 10^3 103次, A A A出现了 B C D ‾ + 1 \overline {BCD}+1 BCD+1次。
这样我们就处理掉了第四位的情况, 直接继续处理第三位的情况即可。
但实际上我们计算了前导 0 0 0的情况, 例如 0999 , 0998 , 0997......0099 , 0098 , 0097..... , 0009 , 0008 , 0007..... 0999,0998,0997......0099,0098,0097.....,0009,0008,0007..... 0999,0998,0997......0099,0098,0097.....,0009,0008,0007.....所以我们需要将 0 0 0的个数减掉 1 0 3 + 1 0 2 + 1 0 1 + 1 0 0 10^3+10^2+10^1+10^0 103+102+101+100。
这样最后的答案就是 s o l v e ( r i g ) − s o l v e ( l e f − 1 ) solve(rig)-solve(lef-1) solve(rig)−solve(lef−1)。
代码如下:
#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 15
#define ll long long
ll tim[MX], pw[MX], cnt1[MX], cnt2[MX];
int buf[MX];
ll lef, rig;
void solve(ll now, ll *cnt)
{
int len = 0; ll tmp = now;
W (now) buf[++len] = now % 10, now /= 10;
for (R int i = len; i; --i)
{
for (R int j = 0; j <= 9; ++j) cnt[j] += tim[i - 1] * buf[i];
for (R int j = 0; j < buf[i]; ++j) cnt[j] += pw[i - 1];
tmp -= buf[i] * pw[i - 1]; cnt[buf[i]] += tmp + 1;
cnt[0] -= pw[i - 1];
}
}
int main(void)
{
scanf("%lld%lld", &lef, &rig);
pw[0] = 1;
for (R int i = 1; i <= 14; ++i) pw[i] = pw[i - 1] * 10, tim[i] = i * pw[i - 1];
solve(lef - 1, cnt1);
solve(rig, cnt2);
for (R int i = 0; i <= 9; ++i) printf("%lld ", cnt2[i] - cnt1[i]);
}