五一欢乐赛——二进制中‘1’的个数

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;
}




你可能感兴趣的:(五一欢乐赛——二进制中‘1’的个数)