数的二进制表示中1的数目

数的二进制表示中1的数目

  • 我们知道, 每一个数都有唯一的二进制表示, 得到一个数的二进制表示, 对减小一些规模巨大的问题的计算复杂度具有重要的意义。那么在这里, 我们想要求得一个数的二进制表示当中1的数目。
  • 首先, 一个最简单的思路就是, 我们求出每一位上的数字再加以统计, 就可以求出这个数的二进制表示当中1的数目, 其代码如下所示:
     
    int__64 Compute(int__64 x)
    {
    int sum =0;
    while(x >0){
    sum += x%2;
    x /=2;
    }
    return sum;
    }

  • 但是, 我们可以想到的是, 计算机在做取余和除法运算的时候, 所需要的代价往往较大, 所以我们就要使用更简单的运算来代替除法和取余运算。
  • 我们知道, 在计算机中储存一个数, 是由这个数的二进制来储存的。所以我们可以使用移位和与的操作来判断最低位的数是1还是0,再加以判断,这样所花费的代价就大大减小了。
     
    int__64 Compute(int__64 x)
    {
    int sum =0;
    while(x >0){
    sum += x&1;
    x = x >> 1;
    }
    return sum;
    }

  • 那么, 还有没有节省时间的方法呢?
  • 我们知道, 我们关心的只是二进制表示中1的数目, 与这中间的0毫无关联, 那么, 如何才能直接找到这个二进制当中的1呢?
  • 我们便想到了减法, 由于二进制中的运算只有3种, 那么做一次减法就可以让最低位上的1借位, 再进行循环的话, 就可以解出二进制码中1的数目了。
     
    int__64 Compute(int__64 x)
    {
    int sum =0;
    while(x >0){
    x &= (x-1);
    sum++;
    }
    return sum;
    }

    这样,这个问题便很快解决了。
  • 更多的, 我想到了去年ACM亚洲区比赛合肥站的一道题, 他要求出比一个数大而且数的二进制表示当中1的数目在指定范围的满足要求的最小的数。
  • 我们使用上面的算法求出1的数目, 按照要求尽可能小的增大目标数。由上面的算法我们可以知道, 减法我们可以增加1的数目, 那么加法就是逆向的操作可以减小1的数目。而若要增大这个数且增加1的数目, 就可以使用或的操作使最低位的0变为1, 具体的代码如下所示:
  • #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define LL long long
    using namespace std;
    LL start;
    int s1, s2;
    int t;
    int Compute(LL st){
        int su =0;
        while(st){
            st =st & (st-1);
            su++;
        }
        return su;
    }
    int main()
    {
        int i;
        scanf("%d",&t);
        for(i =1;i <=t;i++){
            scanf("%lld %d %d",&start,&s1,&s2);
            start+=1;
            while(1){
                int temp =Compute(start);
                if(temp>=s1 && temp<=s2)break;
                else if(temp<s1){
                    LL temp2 =start+1;
                    start =(start | temp2);
                }
                else start++;
            }
            printf("Case #%d: %lld\n",i,start);
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值