O(N)中N的数除数是多少?

时间:2017-11-10 18:45:31

标签: algorithm sieve

因此,我们可以使用筛子计算O(NlogN)算法中每个数字的除数从1到N:

int n;
cin >> n;
for (int i = 1; i <= n; i++) {
    for (int j = i; j <= n; j += i) {
        cnt[j]++; //// here cnt[x] means count of divisors of x
    }
}

有没有办法将它减少到O(N)? 提前谢谢。

4 个答案:

答案 0 :(得分:2)

这个怎么样?从素数2开始,并保留一个元组列表(k, d_k),其中d_kk的除数,从(1,1)开始:

for each prime, p (ascending and lower than or equal to n / 2):
  for each tuple (k, d_k) in the list:
    if k * p > n:
      remove the tuple from the list
      continue
    power = 1
    while p * k <= n:
      add the tuple to the list if k * p^power <= n / p
      k = k * p
      output (k, (power + 1) * d_k)
      power = power + 1
  the next number the output has skipped is the next prime
  (since clearly all numbers up to the next prime are
   either smaller primes or composites of smaller primes)

上面的方法也会生成素数,依靠O(n)内存来继续寻找下一个素数。拥有更高效,独立的素数流可以允许我们避免将任何元组(k, d_k)附加到列表中k * next_prime > n,以及释放保存输出大于n / next_prime的所有内存。

Python code

答案 1 :(得分:2)

这是对@גלעדברקן的解决方案的简单优化。而不是使用集合,使用数组。这大约是设定版本的10倍。

n = 100

answer = [None for i in range(0, n+1)]
answer[1] = 1

small_factors = [1]
p = 1
while (p < n):
    p = p + 1
    if answer[p] is None:
        print("\n\nPrime: " + str(p))
        limit = n / p
        new_small_factors = []
        for i in small_factors:
            j = i
            while j <= limit:
                new_small_factors.append(j)
                answer[j * p] = answer[j] + answer[i]
                j = j * p
        small_factors = new_small_factors

print("\n\nAnswer: " + str([(k,d) for k,d in enumerate(answer)]))

值得注意的是,这也是用于枚举素数的O(n)算法。但是,如果使用从尺寸log(n)/2以下的所有素数生成的轮子,它可以及时创建一个主要列表O(n/log(log(n)))

答案 2 :(得分:0)

考虑这些计数的总和,总和(对于i = 1,n的phi(i))。该总和 O(N log N),因此任何 O(N)解决方案都必须绕过个别计数。

这表明任何改进都需要依赖于先前的结果(动态编程)。我们已经知道phi(i)是每个主要学位加上一个的产物。例如,12 = 2 ^ 2 * 3 ^ 1。度数分别为2和1。 (2 + 1)*(1 + 1)= 6. 12有6个除数:1,2,3,4,6,12。

这“减少”了一个问题,即你是否可以利用先验知识来获得 O(1)直接计算除数的方法,而不必单独计算它们。

考虑一下给定的案例......到目前为止除数计数包括:

1 1
2 2
3 2
4 3
6 4

是否有 O(1)从这些数字中获得phi(12)= 6的方式?

答案 3 :(得分:0)

这是一种理论上比O(n log(n))好的算法,但对于合理n可能更差。我相信其运行时间为O(n lg*(n)),其中lg*https://en.wikipedia.org/wiki/Iterated_logarithm

首先,您可以使用阿特金筛选找到n及时O(n)以内的所有素数。有关详细信息,请参阅https://en.wikipedia.org/wiki/Sieve_of_Atkin

现在的想法是,我们将建立我们的计数列表,只插入一次计数。我们将逐个查看素数因子,并插入值作为最大素数的所有内容。但是,为了做到这一点,我们需要一个具有以下属性的数据结构:

  1. 我们可以在每个值上存储一个值(特别是计数)。
  2. 我们可以在O(1)中向前和向后遍历插入值列表。
  3. 我们可以在i“有效”地找到最后插入的数字。
  4. 插入应该是“有效的”。
  5. (行情是难以估计的部分。)

    第一个是微不足道的,我们的数据结构中的每个槽都需要一个值的位置。第二个可以用双向链表完成。第三个可以通过跳过列表上的聪明变体来完成。第四部分从前三部分落下。

    我们可以使用一组节点(不会开始初始化),并使用下面的字段看起来像一个双向链表:

    1. value我们正在寻找的答案。
    2. prev我们得到答案的最后一个值。
    3. next我们得到答案的下一个值。
    4. 现在如果i位于列表中且j是下一个值,那么跳过列表技巧就是我们也会在prev之后为第一个填充i j 1}},第一个可被4整除,可被8整除,依此类推,直到达到i = 81。因此,如果j = 96prev我们会为82, 84, 8896填写v

      现在假设我们要在现有ki之间的j处插入值k。我们该怎么做呢?我将展示只有i = 81已知的伪代码,然后填写j = 96k = 90k.value := v for temp in searching down from k for increasing factors of 2: if temp has a value: our_prev := temp break else if temp has a prev: our_prev = temp.prev break our_next := our_prev.next our_prev.next := k k.next := our_next our_next.prev := k for temp in searching up from k for increasing factors of 2: if j <= temp: break temp.prev = k k.prev := our_prev

      90

      在我们的特定示例中,我们愿意从90, 88, 80, 64, 0向下搜索prev。但是当我们到达81时,我们实际上被告知8890, 92, 96, 128, 256, ...。我们愿意最多搜索92.prev,但我们必须设置96.prev O(log(k-i) + log(j-k) + 1),我们就完成了。

      现在这是一个复杂的代码,但它的性能是O(log(n))。这意味着它从1.value := 0开始,但随着更多值的填充而变得更好。

      那么我们如何初始化这个数据结构呢?我们初始化一组未初始化的值,然后设置1.next := n+12.prev := 4.prev := 8.prev := 16.prev := ... := 1p。然后我们开始处理我们的素数。

      当我们到达素数n/p时,我们首先搜索x*p, x*p^2, ...下面的上一个插入值。从那里开始向后我们继续插入O(n)的值,直到达到我们的极限。 (向后的原因是我们不想尝试插入,例如,一次为3次,一次为9次。向后移动可以防止这种情况发生。)

      现在我们的运行时间是多少?找到素数是O(n/log(n))。对于另一个O(log(n)),查找初始插入也很容易O(n)时间O(n log(n))的操作。那么所有值的插入呢?这很简单1/log(n)但我们可以做得更好吗?

      首先,填写密度O(n/log(n)) * O(log(n)) = O(n)的所有插入都可以及时完成1/log(log(n))。然后,密度O(n/log(log(n))) * O(log(log(n))) = O(n)的所有插入同样可以及时完成O(lg*(n))。等等越来越多的日志。对于我给出的O(n lg*(n))估算,我们获得的这些因素的数量为O(n)

      我没有证明这个估计和你能做的一样好,但我认为它是。

      所以,不是createProperties(),而是非常接近。

相关问题