如何查找给定范围内的整数数甚至设置了位

时间:2017-01-06 20:06:24

标签: c++ algorithm math binary

我想知道有多少数字表示x,在给定范围内可以说l和r,l< r,表示x的二进制表示中的1的数是偶数。有没有有效的方法来找到它?

2 个答案:

答案 0 :(得分:4)

这是一个关键事实:

  • 如果 n 是一个非负偶数数字,则正好一半的小于 n 的非负整数具有偶数奇偶校验和另一半有奇数奇偶校验。 (“偶校验”表示二进制表示中的位数是偶数。)

假设我们需要使用某些属性 P 来计算[ l r )范围内的整数数,我们知道如何在 l 为0的任何范围内解决此问题。(“[ l r )”是“半开范围”:所有整数 n 其中 l n < r 。这使得算法更容易。)然后我们只需要减去以解决 l ≠0的一般问题:COUNT [ l r )= COUNT [0, r ) - COUNT [0, l )。

第一个事实并不能告诉我们所有我们需要知道的事情,因为它只适用于 n 。但如果 n 是奇数, n-1 是偶数,我们需要做的就是检查 n-1 本身的奇偶校验是不在[0, n -1)范围内的额外数字。

把所有这些放在一起,如果我们有[ l r )的范围,我们按如下方式计算计数:

  • COUNT(0, l l / 2如果 l 是偶数,并且( l - 1)/ 2 + PARITY( l )如果 l 是奇数
  • COUNT(0, r r / 2如果 r 是偶数,并且( r - 1)/ 2 + PARITY( r )如果 r 是奇数
  • COUNT( l r )为COUNT(0, r ) - COUNT(0, l

最后一次计算最多需要两次奇偶校验计算,无论范围有多大,还有几个除法和减法。

如果这是一个数学网站,我可能会觉得有必要在开始时证明关键事实中的断言,但由于这是CS,我将满足于自己的证明大纲。我们首先注意,如果 i 是偶数,那么PARITY( i )和PARITY( i +1)是不同的(因为只有二进制表示)在最后一位有所不同)。相反,如果 i 为奇数,则PARITY( i )和PARITY( i -1)不同。现在,取[0, n 中的所有整数)并将它们分成奇数奇偶校验的整数集和偶数奇偶校验集,并考虑同态

f i )⇒ i +1如果 i 是偶数;
f i )⇒ i -1如果 i 是奇数;

f 在[0, n ]的两个子集之一上的图像是另一个子集,因为 f 的奇偶校验( i )与 i 的奇偶校验不同。所以这两个子集的大小相同。

答案 1 :(得分:0)

假设您的范围属于正整数域,我编写了以下C ++代码

         <td>Korting: <br>

                <input type="checkbox" name="student" value="15">Student 15%<br>
                   <input type="checkbox" name="senior" value="10">Senior 10%<br>
                 <input type="checkbox" name="klant" value="5">Klant 5%<br>
                <hr>
                </td>    
            </tr>
                <tr>
                <td>
                    <input type="submit" width="300px" name="submit" value="Bestellen">
                    <hr>
                    </td>
                    </tr>
                </form>
        </table>
    <!--Shoppingcart eindigt hier-->
    <?php

    if(isset($_POST['submit'])){            

        $aantal = $_POST['aantal'][0];       

         echo "Aantal is: ".$aantal."<br>";            

 if(isset($_POST['student'])){

     $korting = 15;
     echo "Korting is $korting procent";
 }     if(isset($_POST['senior'])){

     $korting = 10;
     echo "Korting is $korting procent";
 }  if(isset($_POST['klant'])){

     $korting = 5;
     echo "Korting is $korting procent";
 }             
 }    

 ?>

</body>

测试范围[7,34]输出:

#include <iostream> 
#include <cmath> 
using namespace std;

int find_even_bits_helper(int upper, int level, bool sign) {
    // find even-bit number starting from 0
    // level and sign just for printing purpose 
    for (int i = 0; i <= level; ++i) cout << ' ';
    cout << "[0," << upper << "] -> " << '\n';
    int answer;
    if (upper == -1) {
        answer = 0;
    }
    else if (upper == 0) {
        answer = 1;
    }
    else if ((upper & (upper + 1)) == 0) {
        answer = (upper + 1) / 2;
    }
    else {
        int threshold = pow(2, floor(log2(upper)));
        int base_part = find_even_bits_helper(threshold - 1, level + 1, sign);
        int extra_part = (upper - threshold + 1) \
                       - find_even_bits_helper(upper - threshold, level + 1, !sign);
        // Essentially remove the highest 1 bit, thus all odd-bit becomes even-bit 
        answer = base_part + extra_part;
    }
    for (int i = 0; i <= level; ++i) cout << ' ';
    if (sign) cout << "+";
    else cout << "-";
    cout << answer << '\n';
    return answer;
}

int find_even_bits(int lower, int upper) {
    return find_even_bits_helper(upper, 0, true) \
         - find_even_bits_helper(lower - 1, 0, false);
}

int main() {
    cout << "Result is: " << find_even_bits(7,34) << '\n';
}

它表明[0,34]有18个偶数位整数,[0,6]有4个偶数位整数。

因此,答案是 [0,34] -> [0,31] -> +16 [0,2] -> [0,1] -> -1 [0,0] -> +1 -1 +18 [0,6] -> [0,3] -> -2 [0,2] -> [0,1] -> +1 [0,0] -> -1 +1 -4 Result is: 14