计算范围内数字的setbits的倒数之和

时间:2014-07-13 04:30:29

标签: c++ algorithm bits counting

如何计算一系列数字[A,B]的设定位的倒数之和 (这里A,B> 0& A,B< 10 ^ 9)?

我的方法:

通过使用从A到B的简单for循环,我使用_builtin_popcount(一个用于计算C / C ++中数字的setbits的内置函数)计算了一个数字的setbits,然后取其倒数并添加。这是一种O(n)方法。但是由于更大的约束,它需要更长的时间。如何进一步优化?是否可以使用O(log(n))算法?

1 个答案:

答案 0 :(得分:2)

F(N, k) = |{m | m is an integer lying in [0, N] and m's binary representation has exactly k bits set}|。您想要的答案是SUM{ (F(B,k) - F(A-1,k))/k | 1<=k<=MSB(B)},其中MSB =最重要的位。

您可以递归计算F(N,k)。正确处理递归的边界。实际的递归是

F(N, k) = F(N^(1<<MSB(N)), k-1) + F((1<<MSB(N))-1, k) 

简而言之,您认为那些与MSB具有相同N的数字和MSBN相同的数字并递归。

运行时为O(log(B)*log(B))

编辑:说明递归:

N = 1101,二进制,k=2<= NMSB相同的数字N{1000, 1001, 1010, 1011, 1100, 1101}。请注意,它们实际上与此集1000 + {000, 001, 010, 011, 100, 101}相同。换句话说,它们都是数字<= N^(1<<MSB(N)) = 1101 ^ 1000 = 101。由于您已经计算了MSB位,因此集合{000, 001, 010, 011, 100, 101}中所需的位数为k-1。这解释了F(N^(1<<MSB(N)), k-1)一词。

<=N的{​​{1}}小于MSB的数字N{000, 001, 010, 011, 100, 101, 110, 111}。换句话说,所有数字<= (1<<MSB(N)) - 1 = 1000 - 1 = 111。到目前为止,您还没有计算任何设置位。因此,您仍需要集合k中的数字{000, 001, 010, 011, 100, 101, 110, 111}位。这就是F((1<<MSB(N))-1, k)术语的来源。