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

前端 未结 6 1998
再見小時候
再見小時候 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 00:54

    I think a key is first understanding the pattern of K values and how rapidly it grows. Basically, you have:

    K(1) = 0
    K(X) = K(bitcount(X))+1 for X > 1
    

    So finding the smallest X values for a given K we see

    K(1) = 0
    K(2) = 1
    K(3) = 2
    K(7) = 3
    K(127) = 4
    K(170141183460469231731687303715884105727) = 5
    

    So for an example like 48238 10^18 9 the answer is trivially 0. K=0 only for 1, and K=1 only for powers of 2, so in the range of interest, we'll pretty much only see K values of 2, 3 or 4, and never see K >= 5

    edit

    Ok, so we're looking for an algorithm to count the number of values with K=2,3,4 in a range of value LO..HI without iterating over the entire range. So the first step is to find the number of values in the range with bitcount(x)==i for i = 1..59 (since we only care about values up to 10^18 and 10^18 < 2^60). So break down the range lo..hi into subranges that are a power of 2 size and differ only in their lower n bits -- a range of the form x*(2^n)..(x+1)*(2^n)-1. We can break down the arbitray lo..hi range into such subranges easily. For each such subrange there will be choose(n, i) values with i+bitcount(x) set bits. So we just add all the subranges together to get a vector of counts for 1..59, which we then iterate over, adding together those elements with the same K value to get our answer.

    edit (fixed again to be be C89 compatible and work for lo=1/k=0)

    Here's a C program to do what I previously described:

    #include 
    #include 
    #include 
    
    int bitcount(long long x) {
        int rv = 0;
        while(x) { rv++; x &= x-1; }
        return rv; }
    
    long long choose(long long m, long long n) {
        long long rv = 1;
        int i;
        for (i = 0; i < n; i++) {
            rv *= m-i;
            rv /= i+1; }
        return rv; }
    
    void bitcounts_p2range(long long *counts, long long base, int l2range) {
        int i;
        assert((base & ((1LL << l2range) - 1)) == 0);
        counts += bitcount(base);
        for (i = 0; i <= l2range; i++)
            counts[i] += choose(l2range, i); }
    
    void bitcounts_range(long long *counts, long long lo, long long hi) {
        int l2range = 0;
        while (lo + (1LL << l2range) - 1 <= hi) {
            if (lo & (1LL << l2range)) {
                bitcounts_p2range(counts, lo, l2range);
                lo += 1LL << l2range; }
            l2range++; }
        while (l2range >= 0) {
            if (lo + (1LL << l2range) - 1 <= hi) {
                bitcounts_p2range(counts, lo, l2range);
                lo += 1LL << l2range; }
            l2range--; }
        assert(lo == hi+1); }
    
    int K(int x) {
        int rv = 0;
        while(x > 1) {
            x = bitcount(x);
            rv++; }
        return rv; }
    
    int main() {
        long long counts[64];
        long long lo, hi, total;
        int i, k;
        while (scanf("%lld%lld%d", &lo, &hi, &k) == 3) {
            if (lo < 1 || lo > hi || k < 0) break;
            if (lo == 0 || hi == 0 || k == 0) break;
            total = 0;
            if (lo == 1) {
                lo++;
                if (k == 0) total++; }
            memset(counts, 0, sizeof(counts));
            bitcounts_range(counts, lo, hi);
            for (i = 1; i < 64; i++)
                if (K(i)+1 == k)
                    total += counts[i];
            printf("%lld\n", total); }
        return 0; }
    

    which runs just fine for values up to 2^63-1 (LONGLONG_MAX). For 48238 1000000000000000000 3 it gives 513162479025364957, which certainly seems plausible

    edit

    giving the inputs of

    48238 1000000000000000000 1
    48238 1000000000000000000 2
    48238 1000000000000000000 3
    48238 1000000000000000000 4
    

    gives outputs of

    44
    87878254941659920
    513162479025364957
    398959266032926842
    

    Those add up to 999999999999951763 which is correct. The value for k=1 is correct (there are 44 powers of two in that range 2^16 up to 2^59). So while I'm not sure the other 3 values are correct, they're certainly plausible.

提交回复
热议问题