题目链接
http://codeforces.com/contest/768/problem/B
题意
给一个数 x,0<=x<=250 ,当这个数大于1时,就把这个数变为x / 2, x % 2, x / 2的序列(这里的除法是整数除法),然后对这个序列接着进行这个操作,直到序列的所有数小于2。随后给出两个数 l,r,0<=r−l<=105 ,问所得序列[l, r]区间的1的个数为多少
思路
很容易看出来这个序列是有规律的,而且这个序列的长度就是大于x的二的幂次中最小的数减1,序列中1的个数当然就是x。
直接上代码吧,非常简单的递推。复杂度
O(logn∗log50)
。
(也看到cf上有人用lowbit来确定某一位是不是1的,很巧妙,大家可以自己去这场比赛的standing上看看前几名的代码)
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 60;
LL bit[MAXN];
LL l, r;
LL n;
LL solve(LL pos, LL n) {
LL len, ret = 0;
while (pos > 0) {
len = *upper_bound(bit, bit + MAXN, n) - 1;
if (pos < (len + 1) / 2) {
n /= 2;
} else {
ret += n / 2 + n % 2;
pos -= (len + 1) / 2;
n /= 2;
}
}
return ret;
// LL len = *upper_bound(bit, bit + MAXN, n) - 1;
// if (pos == (len + 1) / 2) return n / 2 + n % 2;
// else if (pos < (len + 1) / 2) return solve(pos, n / 2);
// else return solve(pos - (len + 1) / 2, n / 2) + n / 2 + n % 2;
}
int main() {
bit[0] = 1;
for (int i = 1; i < MAXN; ++i) bit[i] = bit[i - 1] << 1;
// for (int i = 0; i < MAXN; ++i) cout<<bit[i]<<endl;
while (~scanf("%I64d%I64d%I64d", &n, &l, &r)) {
if (!n) {
puts("0");
continue;
}
printf("%I64d\n", solve(r, n) - solve(l - 1, n));
}
}