题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4588
题意:从a加到b,每次结果加到a上,看在二进制下一共发生了多少次进位。
把0到n的所有数二进制下下来,可以发现规律:第一位循环节为2,每次循环01。第二位循环节是4,每次循环0011。以此类推。
计算两个数的各位分别出现了多少次1,再减掉。模拟进位统计进位次数就可以。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 const int maxn = 10100; 6 LL a, b; 7 LL vis1[maxn], vis2[maxn]; 8 LL vis[maxn]; 9 10 void f(LL* vis, LL x) { 11 memset(vis, 0, sizeof(vis)); 12 for(LL i = 1; i <= 62; i++) { 13 LL t = (1LL << i); 14 LL div = x / t; 15 LL rem = x % t; 16 LL cnt = div * (1LL << (i - 1LL)); 17 cnt += (rem + 1LL) > (t / 2LL) ? rem + 1 - t / 2LL : 0LL; 18 vis[i] = cnt; 19 } 20 } 21 22 int main() { 23 // freopen("in", "r", stdin); 24 // freopen("out.txt", "w", stdout); 25 while(~scanf("%lld%lld",&a,&b)) { 26 f(vis1, a-1); f(vis2, b); 27 memset(vis, 0, sizeof(vis)); 28 for(LL i = 1; i <= 62; i++) { 29 vis[i] = vis2[i] - vis1[i]; 30 } 31 LL ret = 0; 32 for(LL i = 1; i <= 63; i++) { 33 ret += vis[i] / 2LL; 34 vis[i+1] += vis[i] / 2LL; 35 } 36 printf("%lld ", ret); 37 } 38 return 0; 39 }