Description
何老板给你两个非负整数x和y(x<=y),在区间[x,y]中的所有整数,也即是x,x+1,x+2,...,y-1,y这些数字,每个数字对应的二进制数可能包含若干个“1”。总共有多少个“1”呢?
何老板想知道:区间[x,y]中所有数字对应的二进制数中,1总共有多少个?
Input
第一行,两个整数x和y (0<=x<=y<=2,000,000,000)
Output
一行,一个整数,表示所求的结果
Sample Input
1 3
Sample Output
4
Hint
样例说明,在区间[1,3]中共1,2,3三个数字,对应的二进制数分别是1,10,11,数字“1”共出现了4次
分析:
观察一下0-7的二进制数字:
0 => 000
1 => 001
2 => 010
3 => 011
4 => 100
5 => 101
6 => 110
7 => 111
第1位数以01,01......的方式循环;
第2位数以0011,0011的方式循环;
第3位数以00001111,00001111的方式循环;
......以此类推
第k位数以 2^(k-1)个0 + 2^(k-1)个1的方式循环;
令m=k-1;
solve(n,m)表示前n个数第(m+1)位开始一直到最高位的‘1’的个数,容易得到递归方程:
solve(n,m{
if(n==m) return 0;
else return 当前这一位上的‘1’的个数+solve(n,m+1);
}
那么前n个数在当前这一位上的‘1’的个数(记作cur)有多少个呢?
先讨论简单的情况,如果当前这一位(m+1位)为0:
那么‘1’全部来源于完整的周期,那么cur= n/ (2^(m+1)) * (2^m); (用位运算就是右移再左移)
如果这一位不为0:
cur= n/ (2^(m+1)) * (2^m)+来自不完整周期的‘1’的个数;
个数= n% (2^m) +1 (注意为了方便,计数的时候是把0算了进去的没所以要加1);
注意使用 long long
代码如下:
#include<cstdio> #include<iostream> using namespace std; long long solve(int n,int m){ if((n>>m)==0) return 0; int temp=(n>>m)&1,cur; //temp就是第(m+1)位上的数 if(temp==1)cur=((n>>(m+1)<<m))+(n&((1<<m)-1))+1; //(n& ((1<<m)-1) )就是取出前 m-1位,就是n%(2^n); else cur= (n>>(m+1)<<m); return (long long)cur+solve(n,m+1); } int main(){ int x,y; cin>>x>>y; if(x==0)x=1; cout<<solve(y,0)-solve(x-1,0)<<endl; }