Count The Carries
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 1581 Accepted Submission(s): 559
1 2 1 3 1 4 1 6
0 2 3 6题目大意:给出两个十进制数a,b,求区间[a,b]上所有二进制数相加的总进位次数。思路:由于题目数据量很大,所以不可能采取两两相加的形式来计算,而是应该将所有二进制数摞在一起找规律计算。首先给出0——15的二进制表示形式如下0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 1 0 0 1 0 0 0 0 1 0 1 0 0 1 1 0 0 0 1 1 1 0 1 0 0 0 0 1 0 0 1 0 1 0 1 0 0 1 0 1 1 0 1 1 0 0 0 1 1 0 1 0 1 1 1 0 0 1 1 1 1通过观察我们发现最右边一位依次为010101......,倒数第二位为00110011......,即从右边数第n位,其对应的二进制数依次为2^n个0,2^n个1,2^n个0,2^n个1......然后依次循环下去。而每一位所进的位数等于(这一位1的个数+前一位所进的1的个数)/2,而每一位的1是有周期性出现的。这样思路就找到了,即统计每一位的进位个数并相加,最后的总和就是答案。#include<cstdio> #include<cstring> #include<vector> #include<cmath> #include<iostream> #include<algorithm> #include<queue> using namespace std; typedef long long LL; LL solve(LL v, LL i) { LL ans = 0; ans += (v + 1LL) / (1LL << i) * (1LL << (i - 1LL)); //因为算周期时是从0开始算的,所以相应的v也要加1 ans += max( (v + 1LL) % (1LL << i) - (1LL << (i - 1LL)), 0LL ); return ans; } int main() { LL a,b; while (scanf("%I64d %I64d", &a, &b) == 2) { LL sum = 0, id = 0; for (int i = 1; i <= 62; i++) { LL x = solve( max(0LL, a - 1), i ); //分别统计0——(a-1)与0——b中某一位中1的个数,二者的差就是a——b中这一位的1的个数 LL y = solve(b, i); sum += (y - x + id) / 2; //1的个数+进位数 id = (y - x + id) / 2; //进位数 if (!x && !y && !id) break; } printf("%I64d\n",sum); } }
201



被折叠的 条评论
为什么被折叠?



