要检查数字是否为n,请选择r

时间:2013-09-06 16:25:19

标签: combinatorics largenumber integer-arithmetic

有没有一种有效的方法来找到数字n,给定数字N(可能大到10 ^ 18),对于某些n和r,它等于nCr?我们如何找到n的相应最小值?例如

f(20)=6 (20=6C3)  
f(21)= 7 (21=7C2)  
f(22)= 22 (22=22C1)

2 个答案:

答案 0 :(得分:0)

要找到最小值n与使用r<=n/2找到最大值r相同。由于nCr的下限是(2r)Cr=(2r)!/r!,因此要检查的r的数量是有限的。对于10^18,最大值r为31,因为64C32=1.8*10^18

要找到n,对于给定的r,满足N = nCr,可以检查N*r!形式的n*(n-1)*...*(n-r+1)。 n接近(N*r!)^(1/r) + r/2。我认为只需几张支票即可进行测试。

<强>更新

简单的python实现:

from operator import mul  # or mul=lambda x,y:x*y
from fractions import Fraction

def nCk(n,k):
  return int(reduce(mul, (Fraction(n-i, i+1) for i in range(k)), 1))
def M(f,t):
  return reduce(mul, range(f,t+1), 1)

def find_n_r(N):
  for r in range(2, 50): # omit 1, since it is trivial solution
    if nCk(2*r, r) > N:
      return False
    Nr = N * M(1,r)
    nn = pow(Nr, 1./r) + r*0.5
    n = int(nn)
    if M(n-r+1,n) == Nr:
      return n, r
    n += 1
    if M(n-r+1,n) == Nr:
      return n, r  

print find_n_r(nCk(31,7))
print find_n_r(nCk(31,7) + 12)

打印:

(31, 7)
False

答案 1 :(得分:0)

我会给出一个伪代码。该算法在O((N log N) 2 )时间内完成任务。它不够快,但我列出了一些可以显着提高速度的优化。也许有人可以进一步优化这一点。

这里的关键是我们可以确定分割n的素数p的最高幂!对于某些n,p而不计算n!的值,只需在O(log n)时间内查看n。我们表示分割n的p的最高功率!通过hdp(n,p)。 hdp(n,p)可以计算为: hdp(n,p)= floor(n / p)+ floor(n / p 2 )+ ....因此hdp(n,p)可以在log p <中计算/ sub> n time。

首先,我们计算小于或等于n的素数列表。 然后,我们找到N的所有素因子。这将更容易,因为您在步骤1中计算了高达N的素数。设N = p 1 a 1 < /sup>p2a2...pkak

n的上限和下限由Ante在他的解决方案中给出。我们分别称它们为n max 和n min 。然后我们迭代n min 和n max 之间的所有n,对于1到n之间的所有r。现在,N = n C r =(n!)/((nr)!* r!)当且仅当hdp(n,p i < / sub>) - hdp(k,p i ) - hdp(nk,p i )= a i 表示所有i。因此,n-r对最多可以在O((log n) 2 )时间内被修剪。从最大的素因子开始应该是更好的想法,因为程度应该很小。

一些优化:

    对于任何n,
  1. ,你可以找到r所在的范围,而不是迭代所有r从1到n。使用不等式,如 n C r &gt; (n / r) r 等。

  2. 无需考虑n小于p k 的值,其中p k 是N的最大素因子。

  3. 分别求解 n C 2 = N(这只是一个二次方程)。现在,只考虑小于此解决方案的n值。该解决方案将是O(N 1/2 ),因此将时间复杂度降低到O(N(log n) 2 )。为 n C 2 = N和 n C 3 = N执行此操作会将时间复杂度降低到O (N 2/3 (log n) 2 )依此类推。