11

Say we have 3 numbers N, x and y which are always >=1.

N will be greater than x and y and x will be greater than y.

Now we need to find the sum of all number between 1 and N that are divisible by either x or y.

I came up with this:

sum = 0;
for(i=1;i<=N;i++)
{
  if(i%x || i%y)
    sum += i;
}

Is there a way better way of finding the sum avoiding the for loop?

I've been pounding my head for many days now but have not got anything better.

If the value of N has a upper limit we can use a lookup method to speedup the process.

Thanks everyone.

I wanted a C/C++ based solution. Is there a built-in function to do this? Or do I have to code the algorithm?

luke
  • 36,103
  • 8
  • 58
  • 81
user545682
  • 119
  • 1
  • 6
  • 12
    Even if it is homework, at least s/he gave us a solution that s/he worked on. S/he's looking for, maybe, something better. – BeemerGuy Dec 17 '10 at 05:31
  • I feel like this is related to the trick for finding primes but I can't dredge it out of my memory yet – Brad Mace Dec 17 '10 at 05:33
  • @user545682 (or any editor) -- kindly give a more descriptive title, as this is an interesting topic that should be decently searchable. – BeemerGuy Dec 17 '10 at 05:40
  • your condition should be `if (i % x == 0 || i % y == 0) sum += i;` or it'll calculate the sum of numbers that aren't either a multiple of x or y – phuclv Jul 10 '14 at 07:39

2 Answers2

27

Yes. You can void the for loop altogether and find the sum in constant time.

According to the Inclusion–exclusion principle summing up the multiples of x and multiples of y and subtracting the common multiple(s) that got added twice should give us the required sum.

Required Sum = sum of ( multiples of x that are <= N ) +      
               sum of ( multiples of y that are <= N ) -
               sum of ( multiples of (x*y) that are <= N )

Example:

N = 15
x = 3
y = 4

Required sum = ( 3 + 6 + 9 + 12 + 15) +  // multiples of 3
               ( 4 + 8 + 12 ) -          // multiples of 4
               ( 12 )                    // multiples of 12

As seen above we had to subtract 12 as it got added twice because it is a common multiple.

How is the entire algorithm O(1)?

Let sum(x, N) be sum of multiples of x which are less than or equal to N.

sum(x,N) = x + 2x + ... + floor(N/x) * x
         = x * ( 1 + 2 + ... + floor(N/x) )
         = x * ( 1 + 2 + ... + k)    // Where k = floor(N/x)
         = x * k * (k+1) / 2         // Sum of first k natural num = k*(k+1)/2

Now k = floor(N/x) can be computed in constant time.

Once k is known sum(x,N) can be computed in constant time.

So the required sum can also be computed in constant time.

EDIT:

The above discussion holds true only when x and y are co-primes. If not we need to use LCM(x,y) in place of x*y. There are many ways to find LCM one of which is to divide product by GCD. Now GCD cannot be computed in constant time but its time complexity can be made significantly lesser than linear time.

codaddict
  • 445,704
  • 82
  • 492
  • 529
  • 2
    Wow!!Thank you for making it so clear. It looks so simple now. – user545682 Dec 17 '10 at 05:48
  • 2
    Nice answer! One problem, though. If `x` is a multiple of `y`, you only do the first step. – Jim Mischel Dec 17 '10 at 06:08
  • 4
    Nice answer - but you need to use the LCM (lowest common multiple), not `x*y`. For example, if the numbers are 4 and 6, then 12 will get counted twice, but in this case `x*y` is 24. And unfortunately the LCM can't be calculated in constant time, but it *can* be calculated very quickly. – psmears Dec 19 '10 at 10:11
  • 1
    please can you fix your answer - the `x*y` issue means it will sometimes give the wrong answer :-(. For example, `x=4`, `y=6`, `N=12`. Clearly the here answer is `4+6+8+12=30`; your answer will give `(4+8+12)+(6+12)-(0)=42` when it should give `(4+8+12)+(6+12)-(12)=30` - as I mentioned, using the lowest common multiple `LCM(4,6)=12` is crucial here. – psmears Dec 21 '10 at 19:30
  • @psmears: Thanks a lot for noticing the bug :) – codaddict Dec 30 '10 at 03:56
4

If a number is divisible by X, it has to be a multiple of x. If a number is divisible by Y, it has to be a multiple of y.

I believe, if you do a for loop for all multiples of x and y, and avoid any duplicates, you should get the same answer.

Out of my head, something of the type:

sum = 0
for( i=x; i<=n; i+=x)
    sum += i;

for( i=y; i<=n; i+=y)
    if( y % x != 0 )
        sum += i;   
Nican
  • 7,825
  • 3
  • 27
  • 26
  • +1 - beat me to it. Multiples will require fewer comparison operations (although whether or not its actually faster is a different story). – Tim M. Dec 17 '10 at 05:34
  • 1
    @Tim -- as N approaches infinity, I'm sure such a solution gets faster =) – BeemerGuy Dec 17 '10 at 05:39