题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=222
整数中的1
时间限制:
3000 ms | 内存限制:
1000 KB
难度:
4
-
描述
-
给出两个非负32位整型范围内的数a,b,请输出闭区间[a,b]内所有数二进制中各个位的1的总个数。
-
输入
- 一行,给出两个整形数a,b(0<=a<=b<=150000000),空格分隔。 输出
- 一行,输出结果 样例输入
-
1 2
样例输出
-
2
看起来是位运算,但是会超时。。所以要找一下规律。
对于一个数0到n的n+1个数,二进制第一位每2个数会出现1个1,第二位每4个数会出现2个连续的1,第三位每8个数会出现4个连续的1,第四位每16个数会出现8个连续的1。
这样规律就找到了。不过还要考虑一些特例,如果给的n不能正好被整除,多出的那部分只要超过区间的一半,那么超出的那部分一定也是1,因为每个区间中前一半是0,后一半是1。
对于while的结束条件也要好好考虑。
#include <iostream>
#include <cstdio>
using namespace std;
int getnum(int x) {
if(x <= 0) return 0;
int y = x + 1; //因为该规律是从0000开始算起的,相当于一共有x+1个数
int q = 2, p = 1, sum = 0; //每连续q个数出现p个连续的1
while(y >= q / 2) { //位数不够才退出
sum += y / q * p; //加整位
if(y % q > q / 2) sum += y % q - q / 2; //不完整的需要判断是否大于区间的一半,因为每个区间前半部分是0,后半部分是1
q *= 2;
p *= 2;
}
return sum;
}
int main() {
int n, m;
scanf("%d %d", &n, &m);
printf("%d\n", getnum(m) - getnum(n - 1));
return 0;
}