这里start和end的值都在1到2000000000之间。
分析:可以看成求[0, end]内的RoundNumber数 再减去[0, start-1]内的RoundNumber数,具体的求法:对于每一个数A,可以将[0, A]按如下
方式进行分解:分解成位数小于A的所有整数和位数等于A,且小于等于A的所有数。
对位数小于A的所有整数,进一步分解为位数为0,1,2,3,...,A的位数-1的所有整数,位数为0的数集合为空集,位数为1的集合包含0和1,位数为2
的集合包含10和11,位数为3的包含[100,111]这个区间...依次类推,可以预先求出0到31位的所有位数的RoundNumber数,因为2000000000小于
2^31.这里用到组合数,比如求[10000, 11111]区间内的RoundNumber,就是求组合数C(4, 3) + C(4, 4):后面四位中取得0数目要多于1的数目。
对位数等于A且小于等于A的所有整数,比如[10000,11010],按如下方法进行分析:首先分析A本身:11010是否是RoundNumber,然后,再将这个区间进行划分:
[10000, 11000), [11000, 11010), [11010, 11010),就是按1的出现从左向右进行划分, 注意到最后一个区间可能没有值,也可能有一个值,这取决于最后一位
数字是0还是1,然后同样的道理,[11000, 11010)就是[11000, 11001],也是计算组合数。
对于组合数的计算,我们可以发现前面过程中用到的组合数不超过C(31, 31),所以我们可以提前计算出组合数,使用组合数公式:
C(a, b) = C(a-1, b) + C(a-1, b-1); C(x, 0) = 1, 且若b > a C(a, b) = 0求出组合数表。
代码如下:
#include<iostream>
using namespace std;
int numbers[40];
int combNumbers[40][40];
int Comb(int kinds, int choose) {
return combNumbers[kinds][choose];
}
int numOfRNsWithBitsLe(int n){
int comb = 0;
for(int i = 0; i <= n; i++)
comb += numbers[i];
return comb;
}
int conduct(int number) {
int length = 0;
int list[35];
while(number != 0){
list[length] = number % 2;
number = number / 2;
length++;
}
int totalSize = length;
int endCount = numOfRNsWithBitsLe(length - 1);
int oneCount = 0;
int zeroCount = 0;
for(int i = 0; i < length; i++){
int cur = list[i];
if(cur == 1)oneCount++;
else zeroCount++;
}
if(zeroCount >= oneCount)endCount += 1;
if(list[0] == 1){
if(zeroCount + 1 >= oneCount - 1)
endCount++;
}
oneCount = 1; // reuse, different meaning
for(int index = length - 2; index >= 1; index--){
int cur = list[index];
if(cur == 1){
//TODO
int tmp = 2 * index + 2 * oneCount - totalSize;
if(tmp <= 0){
for(int choose = 0; choose <= index; choose++)
endCount += Comb(index, choose);
}
else{
int choose = (tmp % 2 == 0)?tmp / 2:(tmp / 2 + 1);
for(; choose <= index; choose++)
endCount += Comb(index, choose);
}
oneCount++;
}
}
return endCount;
}
void init(){
for(int i = 0; i < 40; i++)
for(int j = 0; j <= i; j++){
if(!j || i == j)
combNumbers[i][j] = 1;
else
combNumbers[i][j] = combNumbers[i-1][j] + combNumbers[i-1][j-1];
}
numbers[0] = 0;
numbers[1] = 1;
for(int n = 2; n < 40; n++){
int oneCount = 1;
int zeroCount = 0;
int bitCount = n - 1;
int choose = (n % 2 == 0)?(n / 2):(n / 2 + 1);
// C(n-1, choose);
int comb = 0;
for(;choose <= bitCount; choose++)
comb += Comb(bitCount, choose);
numbers[n] = comb;
}
}
int main(){
init();
int start,end;
cin>>start>>end;
int nStart = start - 1;
int result1 = conduct(nStart);
int result2 = conduct(end);
int ret = result2 - result1;
cout<< ret <<endl;
}