poj 4588 Count The Carries(数论)

题目:poj 4588 Count The Carries


题目大意:给出x - y,问x一直加到y,二进制的加法,总共进了多少次位。


解题思路:这题需要想到从x加到y,这里的二进制数的每一位有周期性的变化,例如:从1 - 3(十进制)(00,01,10,11),这里的最后一位就是0、1、0、1。而第二位是0、0、1、1。可以发现最后一位是以两个为一周期,往前一位是以4个为一周期,这样第i位(从后数)就是以2^i为一周期。

然后每个位上的1只要有两个就进一次位,这样就需要把每一位上的1都统计出来。因为周期是从0开始的,所以如果要算x到y之间有多少的1,就需要分别统计0 - y 之间的1,然后减去0- (x- 1) 之间的1.

然后再做进位的计算。从低位开始没两个1进一次位,然后进的1的总数要加到高一位的那个1的总数中,要注意:这里可能会有每个位都统计了进位的次数,但是不要忘了最高的那一位如果向前一位进位的次数大于2的话就说明还有进位发生,所以所有的次数还需加上这个数/2.


代码:

#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;

const int N = 35;
long long  x, y;
typedef long long ll;
ll s1[N], s2[N], t[N];
void handle (ll y, ll * s) {
	
	for (int i = 0; i <= 32; i++) {
		
		s[i] = y / t[ i + 1]  * t[i];
		ll d = y % t[i + 1] - t[i];
		s[i] += d > 0 ? d: 0;
	}
}

ll solve () {

	ll ans = 0;
	ll a = 0;
	for (int i = 0; i < 32; i++) {
			
		a  = ( s1[i] - s2[i] + a ) / 2;
		ans += a;
	}
		
	while (a) {

		ans += a / 2;
		a = a / 2;
	}
	return ans;
}

int main () {
	
	t[0] = 1;
	for (int i = 1; i < N; i++)
		t[i] = 2 * t[i - 1];

	while (cin>>x>>y) {
	
		memset (s1, 0, sizeof (s1));
		memset (s2, 0, sizeof (s2));
		handle (y + 1, s1);
		handle (x, s2);
		cout<<solve()<<endl;
	}
	return 0;
}


你可能感兴趣的:(poj 4588 Count The Carries(数论))