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 }