整数中的1(二)

本文介绍了一种高效方法来计算指定范围内所有整数二进制表示中1的总数,包括预处理步骤和查询算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

描述
给出两个非负32位整型范围内的数a,b,请输出闭区间[a,b]内所有数二进制中各个位的1的总个数。
输入
有多组测试数据
每组测试数据只有一行,是两个整型数a,b(0<=a<=b<=150000000),空格分隔。
当a,b都是0时表示输入结束,该组输入不用计算。
测试数据的组数不超过1000组
输出
对于每组输入,输出区间[a,b]内所有数二进制中各个位的1的总个数。
样例输入
1 2
100 200
0 0
样例输出
2
419


本来想到要出一道求1-n中每个数的二进制为1的个数,当n小时,按普通方法就可以了,

当n比较大就需要找规律,将1-15列出来就会发现规律了

1

10

11

100

101

110

111

1000

1001

1010

1011

1100

1101

1110

1111

当二进制位为4位的时候前面2^3个1已经确定了,后面3位就是前面1-3位二进制的和吗?

所以就可以直接预处理就结果算出来,查询的时候只需要算一段就可以了,然后那

一段就可以通过每次去掉前面那个1得到。

#include <stdio.h>
#define LL long long
const int maxn = 55;
LL cnt[maxn], sum[maxn], bit[maxn];
void print ( LL a[] )
{
    for ( int i = 0; i < maxn; i ++ )
        printf ( "%lld ", a[i] );
    printf ( "\n" );
}
//发现位数是按1 2 4 8....增长
LL get_ans ( LL n )
{
    LL ans = 0, t;
    int begin;
    while ( n > 0 )
    {
        begin = 0;
        t = n;
        while ( t >= ( 1 << begin ) )
        {
            t = t-( 1 << begin );
            ans = ans+cnt[begin];
            begin ++;
        }
        if ( t == 0 )   //有可能是2^k-1,那么t就会为0就不需要算了
            break ;
        ans = ans+t;
        n = n & bit[begin]; //去掉前面那个1
    }
    return ans;
}
int main ( )
{
    LL n, m;
    sum[0] = cnt[0] = 1;
    for ( int i = 1; i < maxn; i ++ )
    {
        cnt[i] = ( 1 << i )+sum[i-1]; //将二进制位为i的个数求出来
        sum[i] = sum[i-1]+cnt[i];   //去掉前面一个1就变成i-1,变化即为前i-1的和
        bit[i] = ( 1 << i )-1;  //2^i-1取出最后i位
    }
    while ( ~ scanf ( "%lld%lld", &n, &m ), n || m )
    {
        if ( n == 0 )   //考虑n为0
            n = 1;
        printf ( "%lld\n", get_ans ( m )-get_ans ( n-1 ) );
        //相减就可以了
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值