Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating all divisors of a number given its prime factorization

I want to find all divisors of numbers in range [1,107] . I know it can be solved in O(sqrt(n)). But had to run sieve of Eratosthenes before this which can be easily modified to get prime factorization of a number(by keeping track of one of the prime factors of every number). So i wondering would it be more efficient to generate all the factor using its prime factorization?
Let n = p1k1 * p2k2*....*pmkm

I think this notation can be obtained in O(m+Σki) after sieve.
I came up with following code to generate factors after a bit of thinking:

int factors[]={2,5};        // array containing all the factors
int exponents[]={2,2};      // array containing all the exponents of factors
                            // exponents[i] = exponent of factors[i]
vector <int> ans;           // vector to hold all possible factors

/*
*   stores all possible factors in vector 'ans'
*   using factors and exponents from index l to r(both inclusive)
*/
void gen(int factors[],int exponents[],vector<int>& ans,int l,int r)
{
    if(l==r)                        
    {
        int temp = 1;
        for(int i=0;i<=exponents[l];i++)
        {
            ans.push_back(temp);
            temp *= factors[l];
        }
        return;
    }
    gen(factors,exponents,ans,l+1,r);
    int temp=factors[l];
    int size = ans.size();
    for(int i=1;i<=exponents[l];i++)
    {
        for(int j=0;j<size;j++)
        {
            ans.push_back(ans[j]*temp);
        }
        temp *= factors[l];
    }
}

I think its Time complexity is at least Ω(no of factors) = Ω(∏(1+ki)).

So my question is:
1) Is it faster to generate factors this way than normally(O(sqrt(n)) loop method)?
2) Can the code given above be optimized?

like image 706
Nilesh Hirani Avatar asked Mar 14 '23 05:03

Nilesh Hirani


1 Answers

The first most obvious optimization is to preallocate the answers vector. You know exactly how many factors there will be (since you already gave the formula as ∏(1+ki) ).

If you manage the stack yourself instead of using recursion, you'll get the most optimal solution (each factor will require only 1 lookup and 1 multiplication).

Something like this?

int factors_count = 1;
for (int i = 0; i < r; ++i)
{
    factors_count *= 1+exponents[i];
}
ans.resize(factors_count);
ans[0] = 1;
int count = 1;
for (int stack_level = 0; stack_level < r; ++stack_level)
{
    const int count_so_far = count;
    const int prime = factors[stack_level];
    const int exponent = exponents[stack_level];
    int multiplier = 1;
    for (int j = 0; j < exponent; ++j)
    {
        multiplier *= prime;
        for (int i = 0; i < count_so_far; ++i)
        {
            ans[count++] = ans[i] * multiplier;
        }
    }
}

I haven't even tried compiling it, so caveat emptor.

like image 73
Dmitry Rubanovich Avatar answered Apr 06 '23 10:04

Dmitry Rubanovich