转自: 点击打开链接 http://blog.csdn.net/zhengnanlee/article/details/9794625
题目大意是:
给出a,b两个数,求出之间的round number 数目。
1<=(a,b)<=2,000,000,000
round number 即数字n的二进制中,0的数目不小于1的数目。
下面回顾一下高中关于排列组合的知识:
此为组合排列的基础公式
组合排列具有以下性质:
1>
2>
3>
4>
思路:
1: r(start,end)=r(0,start)-r(0,end-1)=r(0,start+1)-r(0,end)
其中start>end,由此问题转化为求出r(0,n)的值
2: 则问题转为存在一个二进制数n,求出到n的round number 的数目
假设n的二进制数位是len,则存在两种情况
1> len为奇数,毫无疑问最高位是1 即len=k*2+1 则存在2*k个位置可以填充0 或者1,并且保证0 的数目大于1的数目。
由性质2可知
RN(LEN)=
2> len为偶数时,存在len=2*k,则存在2*k-1个数字进行排列组合
同样可得RN(LEN)=
由以上两种情况进行打表
for(i=0;i<=32;i++) for(j=0;j<=i;j++) { if(!j||j==i) map[i][j]=1; else map[i][j]=map[i-1][j-1]+map[i-1][j]; }
3> 对len个数进行排列组合,此时从高位开始向低位进行查找,若该位数字
为1 ,即可对之进行更改变成0,同时在后面进行改动,使0的数目大于1
的数目。
长度为len,改动第i位,此时已存在zero个0(不包括第i位),同
时,需要在之后添加a个1,b个0,则存在两个关系如下:
len=i+a+b && zero+1+b>=len-(zero+1+b)
推得关系: b>=len/2-(zero+1)
即:至少需要添加b个0,之多则为i-1个
代码如下:
#include<stdio.h> #include<string.h> int map[33][33],bin[35]; void Makeout() { int i,j; for(i=0;i<=32;i++) for(j=0;j<=i;j++) { if(!j||j==i) map[i][j]=1; else map[i][j]=map[i-1][j-1]+map[i-1][j]; } } void Make(int p) { bin[0]=0; while(p) { bin[++bin[0]]=p%2; p=p/2; } } int round(int n) { Make(n); int i,j,sum=0; for(i=1;i<bin[0]-1;i++) for(j=i/2+1;j<=i;j++) sum+=map[i][j]; int zero=0; for(i=bin[0]-1;i>=1;i--) { if(bin[i]) for(j=(bin[0]+1)/2-(zero+1);j<=i-1;j++) sum+=map[i-1][j]; else zero++; } return sum; } int main() { int n1,n2; Makeout(); while(scanf("%d%d",&n1,&n2)!=EOF) printf("%d\n",round(n2+1)-round(n1)); }