【数位dp】bzoj1833: [ZJOI2010]count 数字计数
数位dp姿势一直很差啊;顺便庆祝一下1A
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。
题目分析
数位dp经典入门题
说到底,数位dp快就快在按位计算答案,而不是按数计算答案。
这个有些抽象,所以还是看代码吧。
1 #include<bits/stdc++.h> 2 typedef long long ll; 3 4 ll a,b,ans[23]; 5 ll digit[23]; 6 ll base[15]; 7 8 ll read() 9 { 10 char ch = getchar(); 11 ll num = 0; 12 bool fl = 0; 13 for (; !isdigit(ch); ch = getchar()) 14 if (ch=='-') fl = 1; 15 for (; isdigit(ch); ch = getchar()) 16 num = (num<<1)+(num<<3)+ch-48; 17 if (fl) num = -num; 18 return num; 19 } 20 void work(ll num, ll c) 21 { 22 for (digit[0]=0; num; num/=10) 23 digit[++digit[0]] = num%10; 24 for (int i=digit[0]; i; i--) 25 { 26 for (int j=digit[0]; j>i; j--) 27 ans[digit[j]] += c*(digit[i]*base[i]); 28 for (int j=0; j<digit[i]; j++) 29 { 30 for (int k=0; k<=9; k++) 31 ans[k] += c*base[i-1]*(i-1); 32 ans[j] += c*(base[i]); 33 } 34 if (i==digit[0]){ 35 ans[0] -= c*digit[0]; 36 for (int j=1; j<digit[0]; j++) 37 ans[0] -= c*j*base[digit[0]-j]*9; 38 } 39 } 40 } 41 int main() 42 { 43 base[1] = 1; 44 for (int i=2; i<=13; i++) base[i] = base[i-1]*10ll; 45 a = read(), b = read()+1; 46 work(a, -1); 47 work(b, 1); 48 for (int i=0; i<=9; i++) 49 printf("%lld ",ans[i]); 50 return 0; 51 }
END