BZOJ1833: [ZJOI2010]count 数字计数(数位Dp)
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。
解题思路:
考虑一个位置上出现某个数的次数,那么就要考虑其前面的情况*后面的情况就好了。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 typedef long long lnt; 5 lnt p[100]; 6 lnt ans[10]; 7 void solve(lnt lim,lnt f) 8 { 9 if(lim==-1) 10 return ; 11 for(int h=1;p[h-1]<=lim;h++) 12 { 13 lnt di=(lim/p[h-1])%10; 14 lnt dl=lim/p[h]; 15 lnt dr=lim%p[h-1]; 16 if(di) 17 ans[0]+=f*(dl*p[h-1]); 18 else 19 ans[0]+=f*((dl-1)*p[h-1]+dr+1); 20 for(int a=1;a<10;a++) 21 { 22 di=(lim/p[h-1])%10; 23 dl=lim/p[h]; 24 dr=lim%p[h-1]; 25 if(a<di) 26 ans[a]+=f*(p[h-1]*(dl+1)); 27 else if(a==di) 28 ans[a]+=f*(p[h-1]*dl+dr+1); 29 else 30 ans[a]+=f*(p[h-1]*dl); 31 } 32 } 33 return ; 34 } 35 int main() 36 { 37 p[0]=1; 38 for(int i=1;i<=50;i++) 39 p[i]=p[i-1]*10ll; 40 lnt l,r; 41 scanf("%lld%lld",&l,&r); 42 if(l==0) 43 ans[0]++; 44 solve(r,1); 45 solve(l-1,-1); 46 for(int i=0;i<10;i++) 47 printf("%lld ",ans[i]); 48 return 0; 49 }