您的位置:首页 > 其它

NYOJ 222 整数中的1 (二进制位运算,找规律)

2016-05-03 22:05 281 查看
题目链接: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: