3

There are n numbers from 1 to n. I need to find the ∑gcd(i,n) where i=1 to i=n for n of the range 10^7. I used euclid's algorithm for gcd but it gave TLE. Is there any efficient method for finding the above sum?

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
int gcd(int a, int b)
{
    return b == 0 ? a : gcd(b, a % b);
}
int main()
{
   ll n,sum=0;
   scanf("%lld",&n);
   for(int i=1;i<=n;i++)
   {
       sum+=gcd(i,n);
   }
   printf("%lld\n",sum);
   return 0;
}
  • Can you post code you've tried? – Andy M Nov 06 '15 at 13:49
  • 1
    @AndyM I have added the code –  Nov 06 '15 at 13:56
  • I don't see any array called A...Your `i` goes `from 0 to n` and not `from 1 to n`...`n` is read from `cin` while you wrote that `n=10^7`...And I guess `t`is the number of test cases? Maybe you should make your question match your code.... – Simon Kraemer Nov 06 '15 at 14:03
  • @SimonKraemer sorry for the mistakes. i goes from 1 to n and n is of range 10^7 not exactly 10^7. –  Nov 06 '15 at 14:10
  • 3
    `bits/stdc++` Please not. – deviantfan Nov 06 '15 at 14:10
  • Using all prime numbers up to 10^7 (pre-calculated) is not allowed, right? :) – deviantfan Nov 06 '15 at 14:11
  • @deviantfan i dont think it makes any difference. –  Nov 06 '15 at 14:12
  • I'm not sure I understand the problem based on the question. If you are checking for divisors, can you just loop until sqrt(n) -- since divisors come in pairs -- and use that to speed up your loop? – Andy M Nov 06 '15 at 14:17
  • @AndyM He's not searching for all divisors, just for gcd's, which can be calculated in logarithmic time. – deviantfan Nov 06 '15 at 14:21
  • Well, look at that: http://math.stackexchange.com/questions/135351/sum-of-gcdk-n – deviantfan Nov 06 '15 at 14:22
  • @ankitkumar You could use dynamic programming to solve this. You're doing the small numbers a ton of times. – Jonathan Mee Nov 06 '15 at 14:24
  • @deviantfan yes i need to find the sum just like u have provided the link but i am not able to understand that how can i formulate that –  Nov 06 '15 at 14:31
  • Can he store all of the divisors of N and then just iterate through that list with i? – Andy M Nov 06 '15 at 14:31
  • @ankitkumar What are you not understanding? Did you read about the mentioned functions on the linked pages? – deviantfan Nov 06 '15 at 14:34
  • This is Pillai's arithmetical function as in OEIS A018804 Check [Here](https://math.stackexchange.com/questions/135351/sum-of-gcdk-n) – RATHI Apr 08 '18 at 17:45

5 Answers5

6

You can do it via bulk GCD calculation. You should found all simple divisors and powers of these divisors. This is possible done in Sqtr(N) complexity. After required compose GCD table.

May code snippet on C#, it is not difficult to convert into C++

int[] gcd = new int[x + 1];
for (int i = 1; i <= x; i++) gcd[i] = 1;
for (int i = 0; i < p.Length; i++)
    for (int j = 0, h = p[i]; j < c[i]; j++, h *= p[i])
        for (long k = h; k <= x; k += h)
            gcd[k] *= p[i];

long sum = 0;
for (int i = 1; i <= x; i++) sum += gcd[i];

p it is array of simple divisors and c power of this divisor.

For example if n = 125

  • p = [5]
  • c = [3]
  • 125 = 5^3

if n = 12

  • p = [2,3]
  • c = [2,1]
  • 12 = 2^2 * 3^1
Толя
  • 2,839
  • 15
  • 23
  • Using ~80MB won't be possible in such "online judge" stuff, and this actually looks *slower* on the first glance – deviantfan Nov 06 '15 at 14:30
  • Update to 40Mb. 40 and 80 Mb it is ok for current online judges. Complexity very closed to NLogN. – Толя Nov 06 '15 at 14:34
  • Ah, I misread how the loops are nested, due to the indentation before the edit... – deviantfan Nov 06 '15 at 14:36
  • Update: complexity O(N) not a O(NlogN) – Толя Nov 06 '15 at 15:07
  • If you have the factorisation of x then there's no need for all this looping and filling of huge arrays with numbers - simply apply the formulas from the [MathOverflow article](http://math.stackexchange.com/questions/135351/sum-of-gcdk-n) mentioned by deviantfan (S(m*n) = S(m) * S(n) for m,n coprime, and S(p^a) = (a + 1) * p^a + a * p^(a-1) for p prime). That's somewhere between O(log N) and O(sqrt(N)), depending on how you do the factorisation. – DarthGizka Aug 18 '16 at 15:31
1

I've just implemented the GCD algorithm between two numbers, which is quite easy, but I cant get what you are trying to do there. What I read there is that you are trying to sum up a series of GCD; but a GCD is the result of a series of mathematical operations, between two or more numbers, which result in a single value. I'm no mathematician, but I think that "sigma" as you wrote it means that you are trying to sum up the GCD of the numbers between 1 and 10.000.000; which doesnt make sense at all, for me.

What are the values you are trying to find the GCD of? All the numbers between 1 and 10.000.000? I doubt that's it.

Anyway, here's a very basic (and hurried) implementation of Euclid's GCD algorithm:

int num1=0, num2=0;
cout << "Insert the first number: ";
cin >> num1;

cout << "\n\nInsert the second number: ";
cin >> num2;
cout << "\n\n";
fflush(stdin);

while ((num1 > 0) && (num2 > 0))
{
    if ((num1 - num2) > 0)
    {
        //cout << "..case1\n";
        num1 -= num2;
    }
    else if ((num2 - num1) > 0)
    {
        //cout << "..case2\n";
        num2 -= num1;
    }
    else if (num1 = num2)
    {
        cout << ">>GCD = " << num1 << "\n\n";
        break;
    }
}
1

A good place to start looking at this problem is here at the Online Encyclopedia of Integer Sequences as what you are trying to do is compute the sum of the sequence A018804 between 1 and N. As you've discovered approaches that try to use simple Euclid GCD function are too slow so what you need is a more efficient way to calculate the result.

According to one paper linked from the OEIS it's possible to rewrite the sum in terms of Euler's function. This changes the problem into one of prime factorisation - still not easy but likely to be much faster than brute force.

Jackson
  • 5,627
  • 2
  • 29
  • 48
1

I had occasion to study the computation of GCD sums because the problem cropped up in a HackerEarth tutorial named GCD Sum. Googling turned up some academic papers with useful formulas, which I'm reporting here since they aren't mentioned in the MathOverflow article linked by deviantfan.

For coprime m and n (i.e. gcd(m, n) == 1) the function is multiplicative:

gcd_sum[m * n] = gcd_sum[m] * gcd_sum[n]

Powers e of primes p:

gcd_sum[p^e] = (e + 1) * p^e - e * p^(e - 1)

If only a single sum is to be computed then these formulas could be applied to the result of factoring the number in question, which would still be way faster than repeated gcd() calls or going through the rigmarole proposed by Толя.

However, the formulas could just as easily be used to compute whole tables of the function efficiently. Basically, all you have to do is plug them into the algorithm for linear time Euler totient calculation and you're done - this computes all GCD sums up to a million much faster than you can compute the single GCD sum for the number 10^6 by way of calls to a gcd() function. Basically, the algorithm efficiently enumerates the least factor decompositions of the numbers up to n in a way that makes it easy to compute any multiplicative function - Euler totient (a.k.a. phi), the sigmas or, in fact, GCD sums.

Here's a bit of hashish code that computes a table of GCD sums for smallish limits - ‘small’ in the sense that sqrt(N) * N does not overflow a 32-bit signed integer. IOW, it works for a limit of 10^6 (plenty enough for the HackerEarth task with its limit of 5 * 10^5) but a limit of 10^7 would require sticking (long) casts in a couple of strategic places. However, such hardening of the function for operation at higher ranges is left as the proverbial exercise for the reader... ;-)

static int[] precompute_Pillai (int limit)
{
    var small_primes = new List<ushort>();
    var result = new int[1 + limit];

    result[1] = 1;

    int n = 2, small_prime_limit = (int)Math.Sqrt(limit);

    for (int half = limit / 2; n <= half; ++n)
    {
        int f_n = result[n];

        if (f_n == 0)
        {
            f_n = result[n] = 2 * n - 1;

            if (n <= small_prime_limit)
            {
                small_primes.Add((ushort)n);
            }
        }

        foreach (int prime in small_primes)
        {
            int nth_multiple = n * prime, e = 1, p = 1;  // 1e6 * 1e3 < INT_MAX

            if (nth_multiple > limit)
                break;

            if (n % prime == 0)
            {
                if (n == prime)
                {
                    f_n = 1;
                    e = 2;
                    p = prime;
                }
                else break;
            }

            for (int q; ; ++e, p = q)
            {
                result[nth_multiple] = f_n * ((e + 1) * (q = p * prime) - e * p);

                if ((nth_multiple *= prime) > limit)
                    break;
            }
        }
    }

    for ( ; n <= limit; ++n)
        if (result[n] == 0)
            result[n] = 2 * n - 1;

    return result;
}

As promised, this computes all GCD sums up to 500,000 in 12.4 ms, whereas computing the single sum for 500,000 via gcd() calls takes 48.1 ms on the same machine. The code has been verified against an OEIS list of the Pillai function (A018804) up to 2000, and up to 500,000 against a gcd-based function - an undertaking that took a full 4 hours.

There's a whole range of optimisations that could be applied to make the code significantly faster, like replacing the modulo division with a multiplication (with the inverse) and a comparison, or to shave some more milliseconds by way of stepping the ‘prime cleaner-upper’ loop modulo 6. However, I wanted to show the algorithm in its basic, unoptimised form because (a) it is plenty fast as it is, and (b) it could be useful for other multiplicative functions, not just GCD sums.

P.S.: modulo testing via multiplication with the inverse is described in section 9 of the Granlund/Montgomery paper Division by Invariant Integers using Multiplication but it is hard to find info on efficient computation of inverses modulo powers of 2. Most sources use the Extended Euclid's algorithm or similar overkill. So here comes a function that computes multiplicative inverses modulo 2^32:

static uint ModularInverse (uint n)
{
    uint x = 2 - n;

    x *= 2 - x * n;
    x *= 2 - x * n;
    x *= 2 - x * n;
    x *= 2 - x * n;

    return x;
}

That's effectively five iterations of Newton-Raphson, in case anyone cares. ;-)

Community
  • 1
  • 1
DarthGizka
  • 4,347
  • 1
  • 24
  • 36
0

you can use Seive to store lowest prime Factor of all number less than equal to 10^7 and the by by prime factorization of given number calculate your answer directly..

Syed Shibli
  • 992
  • 1
  • 12
  • 15