Description
问区间[a,b]中,有多少个数化成二进制后,0比1多
Input
两个整数a,b
Output
输出区间[a,b]中有多少个数的二进制形式0比1多
Sample Input
2 12
Sample Output
6
Solution
以110100为例,先计算小于100000的有多少个,c(5,2)+c(5,1)。还需要计算100000~110100之间的数量。再将除最高位的1之外的最高的1改为0,以保证后面组合时出现的所有数字小于110100,形如10****。后四位组合数c(4,2)+c(4,1)。再将下一个1变为0,变为1100**。如此依次将各个1变为0,并固定1前面的位,可以帮助我们计算出所有在100000~110100之间的数量
Code
#include<iostream>
#include<stdio.h>
int s,e,C[33][33]={{0}};
int count(int n)
{
if(n<=1)
return 0;
int i,j,res=0,num[33]={0},len=0,zero=0,one=1;//最高位显然是1
while(n)//将n转化成二进制
{
num[len++]=n&1;
n>>=1;
}
for(i=2;i<len;i++)//先将小于n的所有最高位为1且其他位都为0的数计算出来
for(j=(i+1)>>1;j<i;j++)
res+=C[i-1][j];
for(i=len-1;i>0;i--)
if(num[i-1])//若某位为1,则固定前位将该位变为0
{
for(j=i-1;i-1-j+one<=j+zero+1;j--)
res+=C[i-1][j];
one++;//前位1个数加一
}
else//前位0个数加一
zero++;
return res+(zero>=one);
}
int main()
{
int i,j;
C[0][0]=1;
for(i=1;i<33;i++)//打表
{
C[i][0]=1;
for(j=1;j<=i;j++)
C[i][j]=C[i-1][j-1]+C[i-1][j];
}
while(scanf("%d%d",&s,&e)!=EOF)
printf("%d\n",count(e)-count(s-1));
return 0;
}