【问题标题】:count of even numbers having more exponent of 2指数大于 2 的偶数个数
【发布时间】:2020-06-05 12:39:35
【问题描述】:

假设我给了一个数字 n。我想找出所有小于 n 的偶数,并且其素数分解中 2 的指数大于 n 的素数分解中 2 的指数。

如果 n=18 答案是 4,即 4,8,12,16。

使用从 i=2 到小于 n 的 for 循环并检查每个 i 将在代码中显示超出时间限制。

我的方法是计算我将继续除以 2 的次数。但 n=10^18 的限制。所以,我认为它是一个 O (1) 操作。谁能帮我找到任何公式或算法以尽快找到答案?

【问题讨论】:

  • 您要数一数有多少个数,还是要全部打印出来?
  • IIUC 我的回答应该满足您寻找的解决方案
  • 我更新了我的答案,以展示如何获得计数,并在底部提供了一些示例。

标签: algorithm math primes prime-factoring


【解决方案1】:

首先假设 n 是奇数。显然,每个小于 n 的偶数在其因式分解中也有一个更大的指数 2,因此答案将等于 (n−1) / 2。

现在假设 n 等于某个奇数 p 的 2 倍。有 (p-1) / 2 个偶数小于 p,因此也有 (p-1) / 2 个小于 n 且至少可被 22 整除的数。

一般来说,给定任意数 n 等于 2k 乘以某个奇数 q,将有 (q−1) / 2 个小于 n 并且具有更大指数 2 (> 2k) 在他们的因式分解中。

所以这样的功能应该可以工作:

def count_smaller_numbers_with_greater_power_of_2_as_a_factor(n):
    assert n > 0
    while n % 2 == 0:
        n >>= 1
    return (n-1) // 2

示例 1 (n = 18)

  1. 因为 n 是偶数,所以继续除以 2 直到得到奇数。这只需要一步(因为 n / 2 = 9)
  2. 计算小于 9 的偶数个数。这等于 (9−1) / 2 = 4

示例 2 (n = 1018)

  1. 在这种情况下,n = 218 × 518。因此,如果我们继续将 n 减半直到得到一个奇数,结果将是 518
  2. 小于518的偶数个数等于(518-1) / 2 = 1907348632812

【讨论】:

  • 你能举个例子吗,取n=18
  • 假设二进制补码,在 C 和具有类似运算符的语言中,这可以表示为 n / (n & -n) / 2。 (n & -n 找到除以 n 的二的最大幂,因为在 n 中设置的唯一位及其二进制补码是尾随一位。)
  • 对此进行测试,这似乎在不是 2 的幂的数字上效果很好,但在 2 的幂上它没有给出正确的答案。您可以在我的答案中使用 len(findevennumberswithexponentgreaterthan2lessthannum(num)) 进行测试。对于像 670 这样的数字,它给出了正确的答案,即 167。但对于 2 的幂,它没有。例如,实际 10000 的 len 应该是 2500,但这里的等式有答案 312。或者 100 的正确答案是 25,但这个等式给出 12。只是想指出它适用于除 2 的幂以外的数字。
  • @oppressionslayer 如果我正确理解 OP,问题是计算低于某个限制的所有数字,其因子的 更大 幂为 2。例如,从 100 = 25×4,函数应该输出小于 100 且能被 8 整除的整数个数。所以正确答案是 12。对于 2 的任何幂,函数应该输出 0。
【解决方案2】:

您的除法受限于常数 64(对于 10^18~2^64)和复杂性理论中的 O(64)=O(1)。

值分解中的二进制数等于该值二进制表示中的尾随零位数,因此您可以使用位运算(如& 1 和右移shr, >>)来加速代码或应用一些bit tricks

【讨论】:

    【解决方案3】:

    首先,假设n = 2^k * something。求知k

    long k = 0;
    while(n % 2 == 0) { n >>= 1; k++; }
    n <<= k;
    

    既然您知道k 是谁,请将2^k 乘以2 得到大于2^k 的2 的第一次幂:

    long next_power = 1 << (k + 1);  // same as 2^(k + 1)
    

    最后,检查n 是否为奇数。如果不是,打印next_power的所有倍数:

    if(k == 0){  //equivalent to testing n % 2 == 0
        for(long i = next_power; i < n; i += next_power) cout<<i<<endl;
    }
    

    示例:n = 18

    k 将是 1,因为 18 = 2^1 * 9 并且 while 将在那里完成。

    next_power 将是 4 (= 1 &lt;&lt; (k + 1) = 2 ^ (k + 1))。

    for(long i = next_power; i &lt; n; i += next_power) cout&lt;&lt;i&lt;&lt;endl; 将打印 4、8、12 和 16。

    【讨论】:

      【解决方案4】:

      使用我发现的 gcd 技巧很容易做到这一点:

      You can find the count by //4. So 10^18 has 
        In [298]: pow(10,18)//4                                                                                                                                                                            
        Out[298]: 250000000000000000
      
      You can find the count of 18 by //4 which is 4
      
      Fan any numbers that meet your criteria. You can check by using my 
      algorithm here, and taking the len of the array and conpare with the 
      number div//4 to see that that is the answer your looking for: an exact 
      match. You'll notice that it's every four numbers that don't have an 
      exponent of 2. So the count of numbers can be found with //4. 
      
      import math
      
      def lars_last_modulus_powers_of_two(hm):
         return math.gcd(hm, 1<<hm.bit_length())
      
      def findevennumberswithexponentgreaterthan2lessthannum(hm):
          if hm %2 != 0:
            return "only for use of even numbers"
          vv = []
          for x in range(hm,1,-2):
             if  lars_last_modulus_powers_of_two(x) != 2:
                vv.append(x)
          return vv
      

      结果:

      
      In [3132]: findevennumberswithexponentgreaterthan2lessthannum(18)                                                                                                      
      Out[3132]: [16, 12, 8, 4]
      
      

      这是最快的方法,因为您可以跳过模组以获取答案。使用 lars_last_modulus_powers_of_two(num) 立即获得您需要的数字,每个数字一次操作。

      这里有一些例子表明答案是正确的:

      In [302]: len(findevennumberswithexponentgreaterthan2lessthannum(100))                                                                                                                             
      Out[302]: 25
      
      In [303]: 100//4                                                                                                                                                                                    
      Out[303]: 25
      
      In [304]: len(findevennumberswithexponentgreaterthan2lessthannum(1000))                                                                                                                            
      Out[304]: 250
      
      In [305]: 1000//4                                                                                                                                                                                  
      Out[305]: 250
      
      In [306]: len(findevennumberswithexponentgreaterthan2lessthannum(23424))                                                                                                                           
      Out[306]: 5856
      
      In [307]: 23424//4                                                                                                                                                                                 
      Out[307]: 5856
      

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-13
      相关资源
      最近更新 更多