C - Count TheCarries

来源:互联网 发布:注册环保工程师知乎 编辑:程序博客网 时间:2024/05/17 05:13

C - Count TheCarries

现在给你两个数A与B (0<=A<=B<=1000000000),然后要求A与A+1相加,结果再与A+2相加,直到加到B为止。不过过程中做的加法都是数的二进制表示形式的加法。求做的所有加法的二进制进位的总数。比如A+(A+1)共有8次二进制进位,(2A+1)+(A+2)有9次二进制进位,那么A到A+2一共有17次二进制进位。

输入:有最多100000个实例,每个实例用两个整数A,B表示,A=B=0时,表示输入结束。

输出:输出每个实例的进位总数。

分析:对于任意给出的实例A,B只要依次求出X与Y相加时的进位个数就可以。然后再累加入总数即可。

任意XY数相加的二进制进位个数为:X的二进制位个数+Y的二进制位个数-(X+Y)的二进制位个数。比如:

011010

010110

110000

原本X有3个1,Y有3个1,结果(X+Y)只有2个1了,只有在进位的时候会发生原本2个1变成1个1的情况(从而少了一个1)。所有少了几个1就表示进位了几次。

对于从AB的序列依次相加的二进制进位总数为:

A的二进制位数+(A+1)的二进制位数+…B的二进制位数】—【A+(A+1)+…+B的和的二进制位数】

对于每个实例A与B,只要依次计算A,A+1,。。。B的二进制中1的个数,再减去(A+A+1,+…+B)的二进制位个数即可。

以下代码超时:

#include<cstdio>using namespace std;int bitcount(long long x){   if(x==0)return 0;    returnbitcount(x/2)+(x&1);}int main(){    long longa,b;   while(scanf("%lld%lld",&a,&b)==2&&a&&b)    {        longlong bit_sum=0,sum=0;        for(longlong i=a;i<=b;i++)        {           sum+=i;           bit_sum+=bitcount(i);        }       printf("%lld\n",bit_sum-bitcount(sum));    }    return 0;}


解法二:现在想象从A到B所有的数都以二进制的形式叠加在一起相加:

1000111

1001000

1001001

1001010

Sum[64]=0000…4003122(一个数最多64位)

sum[64]保存数加的中间结果,sum[0]表示所有数在2^0的位上二进制的总个数,sum[i]表示所有数在2^i位上二进制的总个数。那么这些不同位上的1相加后进位个个数为:

2^0上的1相加产生的进位,加上 (2^1上的所有1 以及2^0上的1的进位 相加产生的进位),加上…

现在只要求出A到B序列所有数的1的sum表示即可。

如何求0n的所有数的1sum表示?

0n的所有数的二进制和中,第2^i位上1的总数为:

n%2^i+1))-2^i-1 > 0

[ n/2^i+1))]*2^i+n%2^i+1))-2^i-1

n%2^i+1))-2^i-1 <= 0

[n/2^i+1))]*2^i

(自己分析一下2^0位,2^1位,2^2位看看有什么规律)计算一定要小心。

#include<cstdio>using namespace std;int  get(int num[],long long n)//num[i]=j 表计算从0到n的数的二进制和(不进位) 中第2^i位的1的总个数为j个{    for(int i=0;i<64;i++)num[i]=0;    int i;    for(i=0;i<64;i++)    {        if((1LL<<i)>n)break;        num[i]+= ( n/(1LL<<(i+1)) )*(1<<i) ;        if( n%(1LL<<(i+1)) > (1LL<<i)-1 ) num[i] += n%(1LL<<(i+1)) -  ((1LL<<i)-1);    }    return i;}int main(){    int a,b;    while(scanf("%d%d",&a,&b)==2&&a&&b)    {        int num1[64],num2[64];        get(num1,a-1);        get(num2,b);        for(int i=0;i<64;i++)num2[i]-=num1[i];        long long sum=0;        for(int i=0;i<64;i++)        {            sum +=num2[i]/2;            num2[i+1]+=num2[i]/2;        }        printf("%I64d\n",sum);    }    return 0;}



0 0
原创粉丝点击