[ZJOI2010]数字计数
这道题题意清晰明了。
最好的方法用前缀差求,即[0,B]−[0,A−1]。
首先拆位把每位存到数组中,并求出位数L。
然后把这些数当成L位进行统计,不足L位的先补前缀0。
最后减去多余的前缀0即可。
下面求[0,A]各个数出现次数的方法大体是:
例如[0,1320]:
1320中L为4,第一位为1,有一位0在1之前,所以统计0∗∗∗的所有解,而后三位每位一定出现了1000×L/10次,第一位0出现1000次。而1只出现了320次。
取出后三位320,现在只需统计[0,320]中各位出现次数。
有三位0、1、2出现在3之前,所以统计0∗∗、1∗∗、2∗∗的所有解,后两位每位出现了100×L/10,第一位0、1、2分别出现了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 }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步