Algorithm to calculate the number of 1s for a range of numbers in binary

前端 未结 6 1999
再見小時候
再見小時候 2021-01-30 00:39

So I just got back for the ACM Programing competition and did pretty well but there was one problem that not one team got.

The Problem.

6条回答
  •  误落风尘
    2021-01-30 01:02

    This is a full working example with c++17

    #include 
    
    using namespace std;
    
    #define BASE_MAX 61
    
    typedef unsigned long long ll;
    
    ll combination[BASE_MAX][BASE_MAX];
    
    vector> NK(4);
    
    int count_bit(ll n) {
        int ret = 0;
        while (n) {
            if (n & 1) {
                ret++;
            }
            n >>= 1;
        }
    
        return ret;
    }
    
    int get_leftmost_bit_index(ll n) {
        int ret = 0;
        while (n > 1) {
            ret++;
            n >>= 1;
        }
        return ret;
    }
    
    void pre_calculate() {
        for (int i = 0; i < BASE_MAX; i++)
            combination[i][0] = 1;
        for (int i = 1; i < BASE_MAX; i++) {
            for (int j = 1; j < BASE_MAX; j++) {
                combination[i][j] = combination[i - 1][j] + combination[i - 1][j - 1];
            }
        }
    
        NK[0].push_back(1);
        for (int i = 2; i < BASE_MAX; i++) {
            int bitCount = count_bit(i);
            if (find(NK[0].begin(), NK[0].end(), bitCount) != NK[0].end()) {
                NK[1].push_back(i);
            }
        }
        for (int i = 1; i < BASE_MAX; i++) {
            int bitCount = count_bit(i);
            if (find(NK[1].begin(), NK[1].end(), bitCount) != NK[1].end()) {
                NK[2].push_back(i);
            }
        }
        for (int i = 1; i < BASE_MAX; i++) {
            int bitCount = count_bit(i);
            if (find(NK[2].begin(), NK[2].end(), bitCount) != NK[2].end()) {
                NK[3].push_back(i);
            }
        }
    }
    
    
    ll how_many_numbers_have_n_bit_in_range(ll lo, ll hi, int bit_count) {
        if (bit_count == 0) {
            if (lo == 0) return 1;
            else return 0;
        }
    
        if (lo == hi) {
            return count_bit(lo) == bit_count;
        }
    
        int lo_leftmost = get_leftmost_bit_index(lo); // 100 -> 2
        int hi_leftmost = get_leftmost_bit_index(hi); // 1101 -> 3
    
        if (lo_leftmost == hi_leftmost) {
            return how_many_numbers_have_n_bit_in_range(lo & ~(1LL << lo_leftmost), hi & ~(1LL << hi_leftmost),
                                                        bit_count - 1);
        }
    
        if (lo != 0) {
            return how_many_numbers_have_n_bit_in_range(0, hi, bit_count) -
                   how_many_numbers_have_n_bit_in_range(0, lo - 1, bit_count);
        }
    
        ll ret = combination[hi_leftmost][bit_count];
    
        ret += how_many_numbers_have_n_bit_in_range(1LL << hi_leftmost, hi, bit_count);
    
        return ret;
    }
    
    int main(void) {
        pre_calculate();
    
        while (true) {
            ll LO, HI;
            int X;
            scanf("%lld%lld%d", &LO, &HI, &X);
            if (LO == 0 && HI == 0 && X == 0)
                break;
    
            switch (X) {
                case 0:
                    cout << (LO == 1) << endl;
                    break;
                case 1: {
                    int ret = 0;
                    ll power2 = 1;
                    for (int i = 0; i < BASE_MAX; i++) {
                        power2 *= 2;
    
                        if (power2 > HI)
                            break;
                        if (power2 >= LO)
                            ret++;
                    }
                    cout << ret << endl;
                    break;
                }
                case 2:
                case 3:
                case 4: {
                    vector &addedBitsSizes = NK[X - 1];
    
                    ll ret = 0;
    
                    for (auto bit_count_to_added: addedBitsSizes) {
                        ll result = how_many_numbers_have_n_bit_in_range(LO, HI, bit_count_to_added);
                        ret += result;
                    }
    
                    cout << ret << endl;
                    break;
                }
                default:
                    cout << 0 << endl;
                    break;
            }
        }
    
        return 0;
    }
    

提交回复
热议问题