最小公除数


11

基本上,问题是:对于一组正数,找到一个最小数,它不是的任何元素的除数,即。SdSxS, dx

表示n=|S|C=max(S)。考虑函数F(x)=不除x的最小素数x。很容易看到F(x)logx。对于集合S,令F(S)=不除S的任何元素的最小素数S。我们有一个上限

F(S)F(lcm(S))F(Cn)nlogC.

因此,一种简单的蛮力算法(它枚举了从1n \ log C的所有数字,nlogC并检查它是否未除以S的任何元素)S是多项式的,并且具有时间复杂度O(n2logC)

解决该问题的另一种方法是计算S的每个元素的所有因子,S并在蛮力算法中使用它们,以检查x是否为O(1)时间的答案。该算法的时间复杂度为O(nmin(C,nlogC)+nlogC)并且使用O(nlogC)内存,因为我们不需要计算和店内的因素大于nlogC。对于较小的nC其性能更好。

详细来说,该算法包括两部分:

  1. 构造一组S^中的所有元件的所有因素组成的S,即

    xS fnlogC, (fxfS^)
    这可以在O(nmin(C,nlogC))时间和O(nlogC)内存中完成。(这是从哪里来的?对于S的任何元素S,我们可以使用试分解将其分解为最大\ sqrt {C}的所有数字C或将所有素数最大为n \ log C的因子分解nlogC为较小的元素;因此,S的每个元素S可以考虑为时间O(min(C,nlogC))时间。)
  2. 找到最小数。如果检查是否可以在时间内完成,则此步骤需要时间。dS^O(|S^|)=O(nlogC)xS^O(1)

我有两个我感兴趣的问题:

  1. 有没有更快的算法可以解决这个问题?
  2. 对于给定的和,我们如何构造具有最大最小公非因数的集合?nCS

1.“预计算”是指在开始蛮力算法之前。2.分解的复杂度确实是次指数的,请参见。C
SkyterX

@DW在点2上,分解的复杂度在表示数字的位串的长度上是次幂的,但是SkyterX正确地说它是,即与大小的平方根成正比号码。O(C)
Lieuwe Vinkhuijzen

@LieuweVinkhuijzen,这对我来说并不正确。使用GNFS进行分解的复杂度将类似于,它远小于。参见en.wikipedia.org/wiki/…O(exp{1.9(logC)1/3(loglogC)2/3})O(C)
DW

关于第二种方法“对于较小的和 ” 表现更好的说法并不完全正确。仅当它的性能才会更好。因此,为了使第二种方法更好地执行,必须较大(不小)。nCnC/log(C)n
DW

@DW是的,我没有意识到GNFS的复杂性。
Lieuwe Vinkhuijzen

Answers:


6

通过使用更好的整数分解算法,可以改进第二种算法。

这里有两种与整数分解有关的算法:

  • GNFS可以将运行时间为为整数。CO(LC[0.33,1.92])

  • ECM可以找到运行时间为的因数(如果存在;查找所有因素将花费倍的时间(与ECM的运行时间相比相对较小)。nlogCO(LnlogC[0.5,1.41])O(logC/log(nlogC))

这里。Ln[α,c]=exp{c(logn)α(loglogn)1α}

对于运行时间来说,这是一个看起来非常可怕的表达,但是重要的事实是,这比您提到的方法要快。特别地,渐近地比小得多,即GNFS比尝试所有可能的因素快得多。而且渐近地比小得多,也就是说,ECM比尝试所有可能的因子快得多。LC[0.33,1.92]CCLnlogC[0.5,1.41]nlogCnlogC

因此,此方法的总运行时间大约为,这比您的方法更好第一种方法比第二种方法渐近更好。我不知道是否有可能做得更好。O~(nmin(LC[0.33,1.92],LnlogC[0.5,1.41]))


我猜想,任何针对此问题的快速算法都必须包括某种输入集的因式分解。我将检查那些分解算法,但是仍然存在正确测试它们的问题,这引起了我提到的第二个问题,即构造具有最大答案的集合SS
2015年

ECM 在您付出的时间中找到一个因素。如果一个数的所有因子均≤n log C,则需要重复该算法,最多重复log C / log(n log C)次。
gnasher729

3

最小公倍数可能与N log C一样大,但是如果N个数字是随机分布的,那么最小公倍数可能会小很多,可能比N小很多。我会建立其中的表质数是哪个数的除数。

对于每个质数p,我们都有一个索引,这意味着直到该索引的所有数字都已被p进行了运算,并且列出了所有可被其整除的数字。kp

然后,对于d = 2、3、4,...,我们尝试找到可被d整除的数字,或显示没有数字。我们取d的最大素数p。然后,我们检查所有可被p整除的数是否也可被d整除。如果没有找到,那么我们检查更多索引>数字是否可被p整除,更新和可被p整除的数字列表,并检查每个数字是否可被d整除。kpkp

要检查是否存在一个可被p整除的数字,我们检查平均p个数字。稍后,如果我们检查是否有一个数字可被2p整除,则有50%的机会我们只需要检查一个数字(一个可被p整除的数字),而有50%的机会检查另外2p个数字。找到一个可被3p整除的数字很可能很快,依此类推,而且我们永远不会检查N个以上的数字来区分p,因为只有N个数字。

我希望这能解决约可除性检查。N2/logN

PS。随机数的结果有多大?

假设我有N个随机数。N个数字之一可被d整除的概率是1-(1-1 / d)^ N。我假设将1≤d≤k的每个数字作为随机数之一的因子的可能性是通过将这些概率相乘得出的(好吧,这有点狡猾,因为这些概率可能不太完全独立)。

在此假设下,当N = 1000时,数字1..244之一不将任何数字相除的可能性为50%,十亿分之一的数字(直至507)最多将一个数字相除。在N = 10,000的情况下,数字1..1726中的一个不除任何数字的可能性为50%,十亿分之一中的每个数字(直到2979)均除以其中一个数字。

我建议对于N个随机输入,结果的大小比N / ln N大;可能类似于N / ln N *(ln ln N)^ 2。原因如下:

的概率是N个随机数中的至少一个是由随机d整除是。如果d在N附近,则大约是1-exp(-1)≈0.6321。那是一个除数;数d≈N中的每一个都是N个数中至少一个的除数的机会很小,因此最大值d明显小于N。1(11/d)N1(11/d)N

如果d << N,则。1(11/d)N1exp(N/d)

如果d≈N / LN N再按。1exp(N/d)1exp(lnN)=11/N

我们将这些概率添加为大约N / ln N值d,但是对于大多数d而言,结果将显着更大,因此最大d将以某种方式大于N / ln N但显着小于N。

PS。查找可被d整除的数字:

我们选择d的最大素数p,然后首先检查已知可被p整除的数。假设d = kp。然后平均而言,在检查此特定的d时,我们仅检查可被p整除的k个数,对于所有可被p整除的d,我们最多检查所有N个值的可整除性。实际上,对于大多数素数p,我们最有可能检查少于N个值,因为在检查了所有N个值之后,该算法最有可能结束。因此,如果结果为R,则我希望小于N的值除以小于R的每个素数。假设R≤N,则大约为N ^ 2 / log N个检查。

PS。运行一些测试

我使用N = 1,000,000个随机数> 0多次运行了该算法。最不常见的非除数在68,000和128,000之间,并且绝大部分运算在100,000和120,000之间。分割的数量在5.2亿至18亿之间,比(N / ln N)^ 2少得多;大多数案例使用了1000到15亿个分区。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.