dp(i, j, k)表示共i位, 最高位是j, 数字k出现次数. 预处理出来.
差分答案, 对于0~x的答案, 从低位到高位进行讨论
------------------------------------------------------------------------------
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 16;
const int N = 10;
const int L = 14;
ll dp[maxn][maxn][maxn], ans[2][maxn];
void init() {
memset(dp, 0, sizeof dp);
ll power = 1;
for(int i = 0; i < N; i++) dp[1][i][i] = 1;
for(int i = 2; i < L; i++) {
power *= 10LL;
for(int j = 0; j < N; j++) {
dp[i][j][j] += power;
for(int k = 0; k < N; k++)
for(int l = 0; l < N; l++)
dp[i][j][l] += dp[i - 1][k][l];
}
}
}
// [0, x]
void work(ll x, int p) {
if(x < 0) return;
int s[maxn], n = 0;
if(!x) s[++n] = 0;
for(; x; x /= 10) s[++n] = x % 10;
ll cnt = 1, power = 1;
for(int i = 1; i <= n; i++) {
ans[p][s[i]] += cnt;
cnt += power * s[i];
power *= 10LL;
for(int j = (i == n && i != 1); j < s[i]; j++)
for(int k = 0; k < N; k++) ans[p][k] += dp[i][j][k];
for(int j = (i != 2); j < N; j++)
for(int k = 0; k < N; k++)
ans[p][k] += dp[i - 1][j][k];
}
}
int main() {
init();
ll a, b; cin >> a >> b;
work(a - 1, 0); work(b, 1);
for(int i = 0; i < N; i++) {
if(i) putchar(' ');
printf("%lld", ans[1][i] - ans[0][i]);
}
return 0;
}
------------------------------------------------------------------------------
1833: [ZJOI2010]count 数字计数
Time Limit: 3 Sec Memory Limit: 64 MB
Submit: 1995 Solved: 880
[Submit][Status][Discuss]
Description
给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。
Input
输入文件中仅包含一行两个整数a、b,含义如上所述。
Output
输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次。
Sample Input
1 99
Sample Output
9 20 20 20 20 20 20 20 20 20
HINT
30%的数据中,a<=b<=10^6;
100%的数据中,a<=b<=10^12。