尽可能快地找到最多10 ^ 12的总除数?

时间:2012-09-06 17:37:25

标签: python algorithm

我需要计算一个数N的除数总数(不关心除数的值是什么),并且在所有这些数字的40-80次操作中这样做N.我怎么能这样做?这不是一个家庭作业问题。我尝试了Pollard's Rho算法,但即便如此,我的目的太慢了。这是我在python中的代码。如果可能,我该如何改进其性能?

def is_prime(n):    
    if n < 2:
        return False
    ps = [2,3,5,7,11,13,17,19,23,29,31,37,41,
         43,47,53,59,61,67,71,73,79,83,89,97]
    def is_spsp(n, a):
        d, s = n-1, 0
        while d%2 == 0:
            d /= 2; s += 1
        t = pow(int(a),int(d),int(n))
        if t == 1:
            return True
        while s > 0:
            if t == n-1:
                return True
            t = (t*t) % n
            s -= 1
        return False
    if n in ps: return True
    for p in ps:
        if not is_spsp(n,p):
            return False
    return True

def gcd(a,b):
        while b: a, b = b, a%b
        return abs(a)

def rho_factors(n, limit=100):
    def gcd(a,b):
        while b: a, b = b, a%b
        return abs(a)
    def rho_factor(n, c, limit):
        f = lambda x:    (x*x+c) % n
        t, h, d = 2, 2, 1
        while d == 1:
            if limit == 0:
                raise OverflowError('limit exceeded')
            t = f(t); h = f(f(h)); d = gcd(t-h, n)
        if d == n:
            return rho_factor(n, c+1, limit)
        if is_prime(d):
            return d
        return rho_factor(d, c+1, limit)
    if -1 <= n <= 1: return [n]
    if n < -1: return [-1] + rho_factors(-n, limit)
    fs = []
    while n % 2 == 0:
        n = n // 2; fs = fs + [2]
    if n == 1: return fs
    while not is_prime(n):
        f = rho_factor(n, 1, limit)
        n = int(n / f)
        fs = fs + [f]
    return sorted(fs + [n])

def divs(n):
    if(n==1):
        return 1
    ndiv=1
    f=rho_factors(n)
    l=len(f)
    #print(f)
    c=1
    for x in range(1,l):
        #print(f[x])
        if(f[x]==f[x-1]):
            c=c+1
        else:
            ndiv=ndiv*(c+1)
            c=1
       # print ("C",c,"ndiv",ndiv)
    ndiv=ndiv*(c+1)
    return ndiv

3 个答案:

答案 0 :(得分:2)

我记得在SPOJ之前解决了这个问题,但是我不记得我使用的确切方法(如果提供问题ID,它会很棒)。你在这里试过天真的方法了吗?它的复杂度为O(sqrt n),在最坏的情况下约为O(10 ^ 6)。模运算符可能有点慢,但值得尝试一下。以下是在C ++中完成后的外观:

int cntdiv = 0;
for(int i = 2; i * i <= x; i ++) {
    if(x % i == 0) {
        cntdiv += 1 + (i * i != x);
    }
}
//cntdiv is now your count

答案 1 :(得分:2)

首先,您的意思是找到除数的总数,其因子分解中的素数或不同的除数的数量?例如,12 = 2 * 2 * 3有6个除数(1,2,3,4,6,12),其因子分解中有3个素数(2,2,3),2个不同的素数除数(2,3) 。你想要6,3或2作为结果吗?我将假设你想要其余的第二个,但如果你对其他人感兴趣,我认为没有任何重大改变......

其次,你必须完全考虑你的数字。没有已知的捷径可以在没有找到因子本身的情况下找到素数因子的数量。 (除了明显的例外,您可以快速测试因子的数量是== 1还是> = 2。)

10 ^ 12并不是那么大。您只需要测试除数之前的除数,最多为10 ^ 6。比如在2GHz的现代CPU上划分需要20个周期,测试一百万个除数只需要10毫秒。

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
  long long n = atoll(argv[1]);
  for (int i = 2; i < 1000000; i++) {
    while (n % i == 0) { printf("%d\n", i); n /= i; }
  }
  if (n > 1) printf("%lld\n", n);
}

我的机器需要23毫秒。不知道其他13毫秒去了哪里?

Python速度慢了10倍,因为这段代码在我的机器上只需0.23秒:

import sys
n = int(sys.argv[1])
for i in xrange(2, 1000000):
  while n%i==0: print i; n/=i
if n>1: print n

你想要多快?

答案 2 :(得分:-1)

我记得有一个基于数字和其他特征的数字之和的解决方案 例如,3411可以被9整除,因为3 + 4 + 1 + 1 = 9,数字之和可以被9整除,而数字也可以被9整除。其他数字规则是相似的。