poj之3252

  

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



 

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值