hdu 4588 Count The Carries

来源:互联网 发布:php 权限管理 数据 编辑:程序博客网 时间:2024/06/06 20:31

题目:大意就是说给定一个区间[l,r],求出l到r的二进制相加的进位次数。

题解:首先的思路就是暴力,把每个数的二进制形式表示出来,再加起来,不过题目中说,测试数据大约为10000个,测试范围为1-1000000000,这样肯定会超时。然后就考虑,是否能够通过计算把每一二进制位的1的个数求出来,这样就能减少很多时间。首先,看一下1-9的二进制表示法来找一些规律:

这样我们发现,对于第一位二进制位来说,每2个数中有1个1;

                                               对于第二位二进制位来说,每4个数中有2个1;

                                               对于第三位二进制位来说,每8个数中有4个1;

                                               .....

                                               而且还有一点就是,这n/2个数处于n的后一半,那么这样我们就找到了规律,就能通过计算来找到每一位1的个数了。

然后就是模拟每一位的进位,求得l和r分别进位次数,再相减就可以了。

#include <iostream>#include <cstdio>#include <cstring>#include <cmath>using namespace std;__int64 s[70],d[70];int main(){    __int64 a,b;    while(cin>>a>>b)    {        memset(s,0,sizeof(s));        memset(d,0,sizeof(d));        b++;                       //此处b++,为什么?        __int64 k=0,t=2,r=0;        while(a*2>=t)        {            s[k]=(a/t)*t/2;            r=a%t;            if(r>t/2) s[k++]+=r-t/2;            else k++;            t*=2;        }        k=0,t=2,r=0;        while(b*2>=t)        {            d[k]=(b/t)*t/2;            r=b%t;            if(r>t/2) d[k++]+=r-t/2;            else k++;            t*=2;        }        __int64 ans=0;        int c=0;        for(int i=0;i<=25;i++)        {            d[i]-=s[i];        }        for(int i=0;i<=69;i++)        {            c=(d[i]+c)/2;            ans+=c;        }        cout<<ans<<endl;    }    return 0;}


0 0
原创粉丝点击