poj之3252

来源:互联网 发布:mac科研软件 编辑:程序博客网 时间:2024/05/01 14:03

  

 转自: 点击打开链接   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));}



 

  

0 0