[POJ 3286]

How many 0’s?

数学。

比较不擅长的题目类型,虽然一直以来都挺喜欢数学的 ;)

问的是输入unsigned int m和n,问[m, n]的所有数字打印出来后,总共包含多少个0。

题意非常明确的,其实就是要推出函数calc(d),能返回0到d所有0的个数,那么calc(n)-calc(m-1)就是结果。

对于某个具体的d,这里基本的思路是将其包含的数按范围划分,例如d=109250时,首先拆成[0, 100000],[100001, 109000],[109001, 109200]和[109201, 109250]。那么就可以分情况讨论各个范围内数字所含0的总数,最后累加起来即可。

这里采用的方式是从高位开始拆数。例如,将[0, 109250]包括的0拆成三部分:(1)[0, 100000],(2)[0, 9250],(3)以”10″为前缀导致[0, 9250]额外引入的0。那么就可以对[0, 9250]迭代地计算其中包含的0了。也即,此时算法复杂度是和d的位数线性相关的,基本上是O(1)。下面分别讨论三部分含0数目的计算方法。

(1)这里可以预处理,例如a[i]=10^i时,分别计算[1, a[i]]以及[a[i]+1, a[i]*2]范围内所含0的总数,设为b[i]和c[i]。例如a[2]=10^2=100时,b[i]为[1, 100]内0的总数,c[i]为[101, 200]内0的总数。这样处理的原因是,(1)中每次都是拆最高位的,这样当最高位为k时,即为b[i]+(k-1)*c[i]。这里b[i]和c[i]有递推关系,当然其实暴力打表也可以的。

(2)这部分是迭代的,和原本的d处理方法相同;

(3)这部分比较麻烦。首先要记录前缀中含0的个数,然后由d去除最高位后剩余的dd计算需要增加多少个0。这里分情况讨论一下即可。如果前缀有j个0,那么最前面的0包括dd*j个,然后再额外处理后面每一位的情况。

看了别人的基本思路,自己推起来也还是磕磕绊绊。表达起来就更是觉得繁琐了……