Algorithm 如何计算具有一定除数的最小数?

Algorithm 如何计算具有一定除数的最小数?,algorithm,math,Algorithm,Math,从 120的除数是16。事实上,120是有16个除数的最小数 找到具有2**500500除数的最小数。给出你的答案,模为500507 计算n的除数非常简单,例如在Python中len([i代表i在范围内(1,n+1),如果n%i==0])。这是O(n) 我尝试了暴力搜索,发现32除数的最小数字是840,但对于上面的问题来说,速度太慢了。从不等式count\u除数(n)中,除自身外,任何数字的最大除数都是该数字的一半。例如,120本身以外的最大除数为60。因此,您可以轻松地将范围从(n+1)减小到

120的除数是16。事实上,120是有16个除数的最小数

找到具有2**500500除数的最小数。给出你的答案,模为500507

计算n的除数非常简单,例如在Python中
len([i代表i在范围内(1,n+1),如果n%i==0])
。这是O(n)


我尝试了暴力搜索,发现32除数的最小数字是840,但对于上面的问题来说,速度太慢了。从不等式
count\u除数(n)中,除自身外,任何数字的最大除数都是该数字的一半。例如,120本身以外的最大除数为60。因此,您可以轻松地将范围从(n+1)减小到(n/2)

此外,对于一个有m个除数的数字,该数字必须至少((m-1)*2)遵循上述逻辑(-1,因为第m个数字本身就是)。例如,具有4个除数的数字必须至少为6。因此,您对n的搜索范围现在变小了


这两种方法将稍微减少运行时间。

您应该使用整数的除数
n
的公式:

d(n)=(a1+1)(a2+1)…(ak+1)

在哪里

n=p1a1*p2a2*p3a3*…*pkak

是每个整数通过其素因子的幂的唯一表示。这是一个众所周知的公式,但是如果人们想知道如何得到它,请注意,代码> d>代码>将代码< N>代码>如果且仅当代码> d>代码>是p1x1*2x2*p3x3***pkxk的形式,其中席席的每一个都在0和ai之间,所以选择AI的每一个都有AI+ 1的可能性。现在只需应用乘积规则,就可以得到所需的公式

对于固定的
d(n)
(与您的情况一样),
n
的最小值显然是通过仔细选择现有素数的幂或添加新素数来获得的。让我们看一看这个简单的例子,16:

d(x)=(a1+1)(a2+1)…(ak+1)=16=24

这意味着您最多有4个不同的素数,因此:

x=2a1*3a2*5a3*7a4

其中ai>=0。现在的问题是-为了获得
x
的最小值,最好增加2的幂(即增量a1),还是使用7(即取a4=1而不是a4=0)?很容易检查,2*3*5*7>23*3*5=120,这就是为什么在这种情况下120是答案

如何推广这种方法?您应该创建最小堆,在其中放置素数的幂,注意除数的数量达到指定的值。对于16,这个最小堆将包含数字2、3、5、7、22、32、24等。为什么?因为16=24,所以(ai+1)中的每一个都必须除以16,也就是说,它必须是2的幂。每次添加新幂时,它应该将左侧(即变量
d(x)
)的幂增加2,因为您的最终目标是找到具有250000除数的最小数。堆用第一个
k
素数初始化(在问题语句中,
k=500500
),在每个步骤中,当您从堆中弹出px时,返回p2x,并将结果乘以px。
d(x)
=16=24的逐步解决方案:


HTH.

不完整,请回答一些提示:

  • n
  • 的最大整数除数为
    n/2

    因此,不需要检查所有小于或等于
    n

  • 可以使用素数分解

    divisors  | prime_divisors | non_prime_divisors              | LCM(all divisors)
    1         | 1               |                                 | 1
    2         | 1,2             |                                 | 2
    3         | 1,2             | 4                               | 4
    4         | 1,2,3           | 6                               | 6
    5         | 1,2             | 4,8,16                          | 16
    6         | 1,2,3           | 4,6,12                          | 12
    7         | 1,2             | 4,8,16,32,64                    | 64
    8         | 1,2,3           | 4,6,8,12,24                     | 24
    ...
    16        | 1,2,3,5        |4,6,8,10,12,15,20,24,30,40,60,120 | 120
    
    最大素数因子是
    sqrt(n)
    ,因此无需测试
    n
    ,而只需测试
    sqrt(n)
    或超过一半
    n
    位的数字

    m=(2^(ceil(ceil(log2(n))/2)+1))-1
    
    这应该会加快一些速度,但是你需要增加非素数因子的计算

  • 这看起来像某种级数(素数分解)


    因此,试着找到生成这个顺序的方程,然后简单地计算模算术中的第n次迭代(简单的PI运算…
    modmul
    )。我可以看到奇偶元素有独立的方程

  • [edit1]最多可分解16个除数

      1:    1
      2:    1,   2
      3:    1,   2,   4
      4:    1,   2,   3,   6
      5:    1,   2,   4,   8,  16
      6:    1,   2,   3,   4,   6,  12
      7:    1,   2,   4,   8,  16,  32,  64
      8:    1,   2,   3,   4,   6,   8,  12,  24
      9:    1,   2,   3,   4,   6,   9,  12,  18,  36
     10:    1,   2,   3,   4,   6,   8,  12,  16,  24,  48
     11:    1,   2,   4,   8,  16,  32,  64, 128, 256, 512,1024
     12:    1,   2,   3,   4,   5,   6,  10,  12,  15,  20,  30,  60
     13:    1,   2,   4,   8,  16,  32,  64, 128, 256, 512,1024,2048,4096
     14:    1,   2,   3,   4,   6,   8,  12,  16,  24,  32,  48,  64,  96, 192
     15:    1,   2,   3,   4,   6,   8,   9,  12,  16,  18,  24,  36,  48,  72, 144
     16:    1,   2,   3,   4,   5,   6,   8,  10,  12,  15,  20,  24,  30,  40,  60, 120
    

    正如Miljen Mikic解释的那样,除数计数函数是由素因子分解决定的。要计算n,从1开始,使用贪婪算法将除数k倍增加一倍,在每一步选择最便宜的因子。初始成本是素数,使用它们时用它们的平方代替。在预先计算了前k个素数之后,您可以使用最小堆快速完成这项工作。用Python

    import primesieve # pip install primesieve
    import heapq
    
    def solve(k, modulus=None):
        """Calculate the smallest number with 2**k divisors."""
        n = 1
    
        costs = primesieve.generate_n_primes(k) # more than necessary
    
        for i in range(k):
            cost = heapq.heappop(costs)
            heapq.heappush(costs, cost**2)
            n *= cost
            if modulus:
                n %= modulus
    
        return n
    
    assert solve(4) == 120
    
    if __name__ == "__main__":
        print(solve(500500, 500500507))
    

    下面是我的Javascript的高级要点,其中
    factorCount
    表示除数的数量:

    • 找到factorCount的主因子分解
    • 生成这些主要因素的每个独特组合
    • 对于每个组合,从原始素因子数组中提取这些组合值,并在此数组中添加一个值,即提取的值相乘。然后按降序排列元素
    • 对于上一步创建的每个数组,检查在计算2^(b1-1)*3^(b2-1)5^(b3-1)时生成的最小数
    • 此计算的最小数是具有
      因子计数的最小数
      因子数
    下面是我的JavaScript函数的高级代码分解:

    var primeFactors=findPrimeFactors(factorCount);
    var primeFactorCombinations=removeduplicatearray(generateCombinations(primeFactors,1));
    var CombinedFactorConditions=生成组合因子组合(primeFactors,primeFactorCombinations);
    var smallestNumberWithFactorCount=确定最小值(组合因子条件);
    

    下面是完整的沙邦:

    函数smallestNumberByFactorCount(factorCount){
    函数isPrime(primeCandidate){
    var p=2
    
    import primesieve # pip install primesieve
    import heapq
    
    def solve(k, modulus=None):
        """Calculate the smallest number with 2**k divisors."""
        n = 1
    
        costs = primesieve.generate_n_primes(k) # more than necessary
    
        for i in range(k):
            cost = heapq.heappop(costs)
            heapq.heappush(costs, cost**2)
            n *= cost
            if modulus:
                n %= modulus
    
        return n
    
    assert solve(4) == 120
    
    if __name__ == "__main__":
        print(solve(500500, 500500507))
    
    > smallestNumberByFactorCount(3) --> 4
    > smallestNumberByFactorCount(4) --> 6
    > smallestNumberByFactorCount(5) --> 16
    > smallestNumberByFactorCount(6) --> 12
    > smallestNumberByFactorCount(16) --> 120
    > smallestNumberByFactorCount(100) --> 45360
    > smallestNumberByFactorCount(500) --> 62370000
    > smallestNumberByFactorCount(5000) --> 4727833110000
    > smallestNumberByFactorCount(100000000) --> 1.795646397225103e+40
    
    def find_smallest_number(num):
        number2=0
    
        if(num%8==0):
            number2=min(2**((num/4)-1)*3**1*5**1 , 2**((num//2)-1)*3**1)
        elif(num%9==0):
            number2=2**((num/9)-1)*3**2*5**2   
        elif(num%2==0 and num%3==0):
            number2=2**((num/6)-1)*3**2*5**1   
        elif((num%4==0)):
            number2=2**((num/4)-1)*3**1*5**1
        elif(num%2==0):
            number2=2**((num/2)-1)*3**1
        else:
            number2=2**(num-1)         
    
        return number2   
    
    
    num=32
    print("The number of divisors :",num)
    result=find_smallest_number(num)
    print("The smallest number having",num," divisors:",result)
    
    def findfactors(num):
        list1=[]
        for i in range(num,1,-1):
            if num%i==0:
                list1.append(i)
        return list1
    
    def getcombinations(num):
        factors=findfactors(num)
        list1=[]
        if num==1:
            return 1
        for i in factors:
            if getcombinations(num//i)!=1:
                list1.append([i,getcombinations(num//i)])
            else:
                list1.append(i)
        return list1
    
    def unloadlist(list1):
        list2=[]
        if type(list1).__name__=="list":
            for i in list1[1]:
                if type(i).__name__=="list":
                    i=unloadlist(i)
                if type(i).__name__=="list":
                    flag=True
                    for j in i:
                        if type(j).__name__=="list":
                            list2.append([list1[0]]+j)
                            flag=False
                    if flag==True:
                        list2.append([list1[0]]+i)
                else:
                    list2.append([list1[0],i])
            if len(list2)==1:
                list2=list2[0]
        else:
            list2=list1
        return list2
    
    def mergeitems(list1):
        list2=[]
        for i in list1:
            if type(i).__name__=="int":
                list2.append((i,))
            elif type(i).__name__=="list":
                if type(i[0]).__name__!="list":
                    list2.append(tuple(sorted(i,reverse=True)))
                else:
                    for j in i:
                        list2.append(tuple(sorted(j,reverse=True)))
        set1=set(list2)
        return set1
    
    def find_smallest_number(num):
        #start writing your code here
        list1=getcombinations(num)
        for i in range(0,len(list1)):
            list1[i]=unloadlist(list1[i])
        mainlist=mergeitems(list1)
        possibles=[]
        primes=[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, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227]
        for i in mainlist:
            num=1
            for j in range(0,len(i)):
                num*=primes[j]**(i[j] - 1)
            possibles.append(num)
        return min(possibles)
    
    num=7
    print("The number of divisors :",num)
    result=find_smallest_number(num)
    print("The smallest number having",num," divisors:",result)
    
    2**31 * (3...7)**15 * (11...47)**7 * (53...2,713)**3 * (2,719...7,370,029)
    
    Single primes (the last term of the PF) total 499,688.