HDU 4596 (Yet another end of the world)(二进制进位次数和)

题目让求从a加到b的二进制进位次数之和。题目给的是从a到b每次进行两个数的加法,然后求和。

自己YY一下就知道可以从a到b一起做加法,求进位次数和。

具体做法是我们先统计出来从a到b二进制的各位上有多少个1,假如二进制某位有x个1,那么该位进位次数即为x/2,然后给下一位进位x/2。然后把二进制位数扫一遍就行了。

现在的麻烦是怎么统计a到b的二进制的各位上有几个1。通过找规律我们知道:对于二进制的第一位,每两个数中会有1个1。对于二进制的第二位,每四个数中会有2个1。对于二进制的第三位,每八个数中会有4个1,,,对于二进制的第i位,每2^i个数中会有2^(i-1)个1。

于是我们就可以先统计从1到a-1有多少个1,再统计从1到b有多少个1,然后计算出从a到b有多少个1就OK了。具体看cal函数的实现

#pragma warning(disable:4996)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 34;
int num1[N], num2[N], num3[N];

void cal(int a, int *num){
	//先初始化为0
	for (int i = 1; i <= 32; i++)num[i] = 0;
	if (a == 0)return;
	//枚举二进制各个位
	for (int i = 1; i <= 32; i++){
		int T = 1 << i;//二进制第i为的周期为T
		int have = T / 2;//每个周期里含有have个1
		num[i] += (a / T*have);
		//对于不完全的周期,单独统计下
		int left = a%T;
		//找找规律很容易发现这个公式的
		have = left - (1 << (i - 1)) + 1;
		if (have > 0)num[i] += have;
	}
}

int main(){
	int a, b;
	while (~scanf("%d %d", &a, &b)){
		cal(a - 1, num1);
		cal(b, num2);
		int tmp = 0;
		for (int i = 1; i <= 32; i++){
			num3[i] = num2[i] - num1[i];
		}

		LL ans = 0;
		for (int i = 1; i <= 32; i++){
			ans += num3[i] / 2;
			num3[i + 1] += num3[i] / 2;
		}
		while (num3[33]){
			ans += num3[33] / 2;
			num3[33] = num3[33] / 2;
		}
		printf("%lld\n", ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值