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 <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));
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章