bzoj1833 digit

这道题其实挺水,只是写的时候需要想清楚。我的方法是:

1.将[a,b]转化为[0,b+1)-[0,a)

2.预处理出非0的v在区间[0,10^p)出现次数以及0在区间[0,10^p)出现数

3.将一个区间再拆分为几段,如:

12345拆分为[0,10000),[10000,12000),[12000,12300),[12300,12340),[12340,12346)

下面是代码:

 1 #include<cstdio>
 2 using namespace std ; 
 3 
 4 static class digit {
 5     long long pow10 [ 20 ] ;
 6     long long cnt [ 20 ] ;
 7     long long cnt0 [ 20 ] ;
 8 public :
 9     digit () {
10         long long k = 1 ;
11         for ( int i = 0 ; i <= 18 ; ++ i ) {
12             pow10 [ i ] = k ;
13             k *= 10 ;
14         }
15         cnt0 [ 0 ] = 1 ;
16         for ( int i = 1 ; i <= 18 ; ++ i ) {
17             cnt [ i ] = pow10 [ i - 1 ] + cnt [ i - 1 ] * 10 ;
18             //printf ( "%lld\n" , cnt [ i ] ) ;
19             cnt0 [ i ] = cnt [ i - 1 ] * 9 + cnt0 [ i - 1 ] ;
20             //printf ( "%lld\n" , cnt0 [ i ] ) ;
21         }
22     }
23     long long operator () ( long long x , const int v ) {
24         x += 1 ;
25         int w = -1 ; while ( pow10 [ ++ w ] < x ) ;
26         int c = 0 ; long long ans = 0 ;
27         if ( v == 0 ) {
28             ans += cnt [ w ] * ( x / pow10 [ w ] - 1 ) + cnt0 [ w ] ;
29             x %= pow10 [ w -- ] ;
30         }    
31         while ( x ) {
32             ans += c * ( x / pow10 [ w ] * pow10 [ w ] ) + cnt [ w ] * ( x / pow10 [ w ] ) + ( x / pow10 [ w ] > v ? pow10 [ w ] : 0 ) ;
33             c += ( x / pow10 [ w ] == v ) ;
34             x %= pow10 [ w -- ] ;
35         }
36         return ans ;
37     }
38 } DIGIT ;
39 
40 long long a , b ;
41 int main () {
42     scanf ( "%lld%lld" , & a , & b ) ;
43     printf ( "%lld" , DIGIT ( b , 0 ) - DIGIT ( a - 1 , 0 ) ) ;
44     for ( int i = 1 ; i < 10 ; ++ i ) printf ( " %lld" , DIGIT ( b , i ) - DIGIT ( a - 1 , i ) ) ;
45     putchar ( '\n' ) ;
46     return 0 ;
47 }

 

posted @ 2016-01-11 19:38  Chris_2  阅读(178)  评论(0编辑  收藏  举报