codeforces 399 B. Code For 1 递推 规律

题目链接

http://codeforces.com/contest/768/problem/B

题意

给一个数 x,0<=x<=250 ,当这个数大于1时,就把这个数变为x / 2, x % 2, x / 2的序列(这里的除法是整数除法),然后对这个序列接着进行这个操作,直到序列的所有数小于2。随后给出两个数 l,r,0<=rl<=105 ,问所得序列[l, r]区间的1的个数为多少

思路

很容易看出来这个序列是有规律的,而且这个序列的长度就是大于x的二的幂次中最小的数减1,序列中1的个数当然就是x。
直接上代码吧,非常简单的递推。复杂度 O(lognlog50)
(也看到cf上有人用lowbit来确定某一位是不是1的,很巧妙,大家可以自己去这场比赛的standing上看看前几名的代码)

代码

#include 
#include 
#include 
#include 
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<while (~scanf("%I64d%I64d%I64d", &n, &l, &r)) {
        if (!n) {
            puts("0");
            continue;
        }
        printf("%I64d\n", solve(r, n) - solve(l - 1, n));
    }
}

你可能感兴趣的:(codeforces 399 B. Code For 1 递推 规律)