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

前端 未结 6 1942
再見小時候
再見小時候 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:48

    Zobgib,

    The key to this problem is not to understand how rapidly the growth of K's pattern grows, but HOW it grows, itself. The first step in this is to understand (as your coach said) how binary numbers count, as this determines everything about how K is determined. Binary numbers follow a pattern that is distinct when counting the number of positive bits. Its a single progressive repetitive pattern. I am going to demonstrate in an unusual way...

    Assume i is an integer value. Assume b is the number of positive bits in i
    i = 1; 
    b = 1; 
    
    i = 2; 3;
    b = 1; 2;
    
    i = 4; 5; 6; 7;
    b = 1; 2; 2; 3;
    
    i = 8; 9; 10; 11; 12; 13; 14; 15;
    b = 1; 2;  2;  3;  2;  3;  3;  4;
    
    i = 16; 17; 18; 19; 20; 21; 22; 23; 24; 25; 26; 27; 28; 29; 30; 31;
    b =  1;  2;  2;  3;  2;  3;  3;  4;  2;  3;  3;  4;  3;  4;  4;  5; 
    
    I assure you, this pattern holds to infinity, but if needed you
    should be able to find or construct a proof easily.
    

    If you look at the data above, you'll notice a distinct pattern related to 2^n. Each time you have an integer exponent of 2, the pattern will reset by including the each term of previous pattern, and then each term of the previous pattern incremented by 1. As such, to get K, you just apply the new number to the pattern above. The key is to find a single expression (that is efficient) to receive your number of bits.

    For demonstration, yet again, you can further extrapolate a new pattern off of this, because it is static and follows the same progression. Below is the original data modified with its K value (based on the recursion).

    Assume i is an integer value. Assume b is the number of positive bits in i
    i = 1; 
    b = 1; 
    K = 1;
    
    i = 2; 3;
    b = 1; 2;
    K = 1; 2;
    
    i = 4; 5; 6; 7;
    b = 1; 2; 2; 3;
    K = 1; 2; 2; 3;
    
    i = 8; 9; 10; 11; 12; 13; 14; 15;
    b = 1; 2;  2;  3;  2;  3;  3;  4;
    K = 1; 2;  2;  3;  2;  3;  3;  2;
    
    i = 16; 17; 18; 19; 20; 21; 22; 23; 24; 25; 26; 27; 28; 29; 30; 31;
    b =  1;  2;  2;  3;  2;  3;  3;  4;  2;  3;  3;  4;  3;  4;  4;  5; 
    K =  1;  2;  2;  3;  2;  3;  3;  2;  2;  3;  3;  2;  3;  2;  2;  3;
    

    If you notice, K follows a similar patterning, with a special condition... Everytime b is a power of 2, it actually lowers the K value by 2. Soooo, if you follow a binary progression, you should be able to easily map your K values. Since this pattern is dependant on powers of 2, and the pattern is dependant upon finding the nearest power of 2 and starting there, I propose the following solution. Take your LOW value and find the nearest power of 2 (p) such that 2^p < LOW. This can be done by "counting the bits" for just the lowest number. Again, once you know which exponent it is, you don't have to count the bits for any other number. You just increment through the pattern and you will have your b and hence K (which is following the same pattern).

    Note: If you are particularly observant, you can use the previous b or K to determine the next. If the current i is odd, add 1 to the previous b. If the current i is divisible by 4, then you decrement b by either 1 or 2, dependent upon whether it's in the first 1/2 of the pattern or second half. And, of course, if i is a power of 2, start over at 1.

    Fuzzical Logic

    Pseudo-code Example (non-Optimized)

    {   var LOW, HIGH
        var power = 0

    //Get Nearest Power Of 2 for (var i = 0 to 60) { // Compare using bitwise AND if (LOW bitAND (2 ^ i) = (2 ^ i)) { if ((2 ^ i) <= LOW) { set power to i } else { // Found the Power: end the for loop set i to 61 } } }

    // Automatically 1 at a Power of 2 set numOfBits to 1 array numbersWithPositiveBits with 64 integers = 0 // Must create the pattern from Power of 2 set foundLOW to false for (var j = (2^power) to HIGH) { set lenOfPatten to (power + 1) // Don't record until we have found the LOW value if ((foundLOW is false) bitAND (j is equal to LOW)) { set foundLOW to true } // If j is odd, increment numOfBits if ((1 bitAND j) is equal to 1) { increment numOfBits } else if (j modulus 4 == 0) { decrement numOfBits accordingly //Figure this one out yourself, please } else if ((j - (2^power)) == (power + 1)) { // We are at the next power increment power // Start pattern over set numOfBits to 1 } // Record if appropriate if (foundLOW is equal to true) { increment element numOfBits in array numbersWithPositiveBits } }

    // From here, derive your K values.

提交回复
热议问题