题目:大意就是说给定一个区间[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;
}