PKU 3286

最近变懒了。。。很不想写解题报告。。不想写博客。。。

今天又做了一道以前做过类似的枚举题的,可惜忘记了,不会推了,推了大半天,还看下以前的代码。。表示很戳。。。很弱。。。

http://acm.pku.edu.cn/JudgeOnline/problem?id=3286

题意给定区间,求出区间(n,m)里面0 的个数。。。

想法:分别算出<=n g(n),<=m g(m)的个数 , 然后枚举n里面0的个数,答案就是g(m) - g(n) +n里面0的个数。

问题关键:如何求<= m的数,现在我们把m拆开来看,从数的末尾枚举m的每一位,那么枚举第i位的时候,第0~i-1位的数记为left,第i+1~最后 的 数字记为right;此时查看第i位:

                       1 若此为本身为 0 , 就是说原数字里面本身有一个0 , 然后求出比 ----0------小的数+1   加至 sum ;              

                       2 若次数不为0,则原数该位没0,那么显然小余----0-----的数都是小于原数的, 算出   加至 sum ;

重复以上两个过程,直至left < 10 ;

比如:求小于等于 5010  的0的个数;

         设digit为第i位的数字;

         sum = 1;

        1 枚举第4 位时,left = 501 , right = 0 ,digit = 0 ;

                               显然   500 0 , 499 0 , 498 0 , …… …… ,3 0 , 2 0, 1 0  ;  都是<5010 的 ,然后+5010 中的最后一个0;

                                sum += (left - 1)*10^0  + right  + 1 =  502 ;

        2 枚举第2位时,left = 50 , right =  10 , digit = 1 ; 

                               显然   50 0 X  , 49 0 X, 48 0 X, ………… 2 0 X, 1 0 X ; 显然都是  < 5010  的 ; 其中 X =0 ,1,2,3,4,5,6,7,8,9;  

                               sum += left *10 ;   

        依照上面的循环下去即可。。。

表示这种模型 要记住了。。不能在忘了。。。希望写篇blog能加深印象。。。

代码:

#include<stdio.h> typedef unsigned long long ULL; ULL calNum(unsigned m) { ULL sum = 1; unsigned digit, left=m, right = 0, pow10 = 1; while(1) { if(left < 10) break; digit = left%10 ; left /= 10 ; sum += digit ? left*pow10 : (left-1)*pow10+right+1 ; right = digit*pow10+right ; pow10 *= 10 ; } return sum ; } ULL meJu(unsigned m) { ULL tmp = 0; do{ if(m%10 == 0) tmp++; m /= 10 ; }while(m) ; return tmp ; } int main() { long long n,m; while(scanf("%lld%lld",&n,&m) && (n!=-1 && m!=-1)) { printf("%llu/n",calNum((unsigned)m)-calNum((unsigned)n)+meJu((unsigned)n)); } return 0; }

                                                                

你可能感兴趣的:(Blog)