1. 程式人生 > >BZOJ1833: [ZJOI2010]count 數字計數(數位Dp)

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 }