Processing math: 100%

[ZJOI2010]数字计数

这道题题意清晰明了。

最好的方法用前缀差求,即[0,B][0,A1]

首先拆位把每位存到数组中,并求出位数L

然后把这些数当成L位进行统计,不足L位的先补前缀0

最后减去多余的前缀0即可。

下面求[0,A]各个数出现次数的方法大体是:

例如[0,1320]

1320L4,第一位为1,有一位01之前,所以统计0的所有解,而后三位每位一定出现了1000×L/10次,第一位0出现1000次。而1只出现了320次。

取出后三位320,现在只需统计[0,320]中各位出现次数。

有三位012出现在3之前,所以统计012的所有解,后两位每位出现了100×L/10,第一位012分别出现了100次,而3只出现了20次。

取出后两位20,便只要统计[0,20]中各位出现次数了。

后面略。

下面的写法就是将上面的理解抽象。

复制代码
 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 #define re register
 6 #define rep(i, a, b) for (re int i = a; i <= b; ++i)
 7 #define repd(i, a, b) for (re int i = a; i >= b; --i)
 8 #define maxx(a, b) a = max(a, b);
 9 #define minn(a, b) a = min(a, b);
10 #define LL long long
11 #define inf (1 << 30)
12 
13 inline LL read() {
14     LL w = 0, f = 1; char c = getchar();
15     while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar();
16     while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ '0'), c = getchar();
17     return w * f;
18 }
19 
20 const int maxl = 16;
21 
22 LL f1[maxl], f2[maxl], A, B, p[maxl];
23 int L, bit[maxl];
24 
25 void make(LL x) {
26     L = x ? 0 : 1;
27     while (x) bit[++L] = x % 10, x /= 10;
28 }
29 
30 void solve(LL *f, LL V) {
31     rep(i, 1, L-1) f[0] -= p[i]; 
32     while (L) {
33         rep(i, 0, bit[L]-1) f[i] += p[L-1];
34         if (L>1) rep(i, 0, 9) f[i] += bit[L] * p[L-2] * (L-1);
35         V -= bit[L] * p[L-1];
36         f[bit[L]] += V+1; L--;
37     }
38 }
39 
40 int main() {
41     p[0] = 1;
42     rep(i, 1, 14) p[i] = p[i-1] * 10;
43 
44     A = read(), B = read();
45     make(A-1); solve(f1, A-1);
46     make(B); solve(f2, B);
47     rep(i, 0, 9) printf("%lld ", f2[i] - f1[i]);
48     return 0;
49 }
复制代码

 

posted @   AC-Evil  阅读(355)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示