13

How can I sum the following sequence:

⌊n/1⌋ + ⌊n/2⌋ + ⌊n/3⌋ + ... + ⌊n/n⌋

This is simply O(n) solution on C++:

#include <iostream>
int main()
{
   int n;
   std::cin>>n;
   unsigned long long res=0;
   for (int i=1;i<=n;i++)
   {
      res+= n/i;
   }
   std::cout<<res<<std::endl;
   return 0;
}

Do you know any better solution than this? I mean O(1) or O(log(n)). Thank you for your time :) and solutions

Edit: Thank you for all your answers. If someone wants the solution O(sqrt(n)): Python:

import math
def seq_sum(n):
 sqrtn = int(math.sqrt(n))
 return sum(n // k for k in range(1, sqrtn + 1)) * 2 - sqrtn ** 2
n = int(input())
print(seq_sum(n))

C++:

#include <iostream>
#include <cmath>
int main()
{
   int n;
   std::cin>>n;
   int sqrtn = (int)(std::sqrt(n));
   long long res2 = 0;
   for (int i=1;i<=sqrtn;i++)
   {
      res2 +=2*(n/i);
   }
   res2 -= sqrtn*sqrtn;
   std::cout<<res2<<std::endl;
   return 0;
}
vasylysk
  • 132
  • 10
  • Is `O(sqrt(n))` fine? – kraskevich Jan 04 '15 at 18:05
  • @ILoveCoding: Feel free to post that as an answer even though it's not O(1). If it's correct, I for one would upvote that. – NPE Jan 04 '15 at 18:11
  • 3
    This seems very relevant for an `O(1)` solution: http://math.stackexchange.com/questions/740442/how-do-i-evaluate-this-suminvolving-the-floor-function – Alec Jan 04 '15 at 18:15
  • 2
    See references in [A006218](http://oeis.org/A006218), there's mention of an O(n^1/3) algorithm. – Kerrek SB Jan 04 '15 at 18:15

6 Answers6

24

This is Dirichlet's divisor summatory function D(x). Using the following formula (source)

D(x)

where

u

gives the following O(sqrt(n)) psuedo-code (that happens to be valid Python):

def seq_sum(n):
  sqrtn = int(math.sqrt(n))
  return sum(n // k for k in range(1, sqrtn + 1)) * 2 - sqrtn ** 2

Notes:

  • The // operator in Python is integer, that is truncating, division.
  • math.sqrt() is used as an illustration. Strictly speaking, this should use an exact integer square root algorithm instead of floating-point maths.
NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • I'm not the downvoter, but shouldn't your pseudo-code involve floor functions as `u = floor(sqrt(x))`, same with `x/k`. Also I think this estimates the sum of the series, not giving exact sum. – mip Jan 04 '15 at 19:08
  • @doc: The `//` operator in Python is integer (truncating) division. – NPE Jan 04 '15 at 19:09
  • @doc: And it does give the exact sum, so long as the integer square root is exact. – NPE Jan 04 '15 at 19:12
  • @NPE ah, OK then. Nice. – mip Jan 04 '15 at 19:13
7

Taken from the Wikipedia article on the Divisor summatory function,

enter image description here

where enter image description here. That should provide an enter image description here time solution.

EDIT: the integer square root problem can also be solved in square root or even logarithmic time too - just in case that isn't obvious.

Alec
  • 31,829
  • 7
  • 67
  • 114
5

The Polymath project sketches an algorithm for computing this function in time O(n^(1/3 + o(1))), see section 2.1 on pages 8-9 of:

http://arxiv.org/abs/1009.3956

The algorithm involves slicing the region into sufficiently thin intervals and estimating the value on each, where the intervals are chosen to be thin enough that the estimate will be exact when rounded to the nearest integer. So you compute up to some range directly (they suggest 100n^(1/3) but you could modify this with some care) and then do the rest in these thin slices.

See the OEIS entry for more information on this sequence.

Edit: I now see that Kerrek SB mentions this algorithm in the comments. In fairness, though, I added the comment to the OEIS 5 years ago so I don't feel bad for posting 'his' answer. :)

I should also mention that no O(1) algorithm is possible, since the answer is around n log n and hence even writing it out takes time > log n.

Charles
  • 11,269
  • 13
  • 67
  • 105
1

Let's divide all number {1, 2, 3, ..., n} into 2 groups: less than or equal to sqrt(n) and greater than sqrt(n). For the first group, we can compute the sum by simple iteration. For the second group, we can use the following observation: if a > sqrt(n), than n / a < sqrt(n). That's why we can iterate over the value of [n / i] = d (from 1 to sqrt(n)) and compute the number of such i that [n / i] = d. It can be found in O(1) for a fixed d using the fact that [n / i] = d means i * d <= n and i * (d + 1) > n, which gives [n / (d + 1)] < i <= [n / d].

The first and the second groups are processed in O(sqrt(n)), which gives O(sqrt(n)) time in total.

kraskevich
  • 18,368
  • 4
  • 33
  • 45
0

For large n, use the formula:

enter image description here

where enter image description here

(enter image description here is a transcendental number.)

See the Euler-Mascheroni constant article for more information.

Community
  • 1
  • 1
Danny Daglas
  • 1,501
  • 1
  • 9
  • 9
  • 4
    Does this take into account the rounding down of each term? (I didn't downvote BTW.) – NPE Jan 04 '15 at 18:13
  • 1
    Yes as the intent is to use the closed form after the 2nd equals, not to loop through each fraction. – Danny Daglas Jan 04 '15 at 18:14
  • 1
    Not obvious why this answer is problematic, someone who downvoted should leave a comment as to why they did so – asimes Jan 04 '15 at 18:16
  • 3
    @asimes: I didn't downvote, but for starters it doesn't return an integer whereas clearly the sequence in the question adds up to an integer. – NPE Jan 04 '15 at 18:19
  • Woaw, I didn't take the flooring into account. Sorry. You are right. I should have noticed the floor operator around each fraction. – Danny Daglas Jan 04 '15 at 18:26
  • @asimes: The first equality is wrong because it doesn't take into account rounding down -- it gives an upper bound rather than an equality. (That quantity minus n would be a lower bound.) The second equality is wrong because it drops the error term. Also, the log in the second term is wrong. (I didn't downvote, though.) – Charles Jan 04 '15 at 19:28
  • Not the downvoter, but I'd also point out (in addition to what @Charles said) that you have written $e = 0.5772\ldots$, when normally the symbol $e$ is reserved to mean $2.71828\ldots$. Also, I don't see why you'd say that $\gamma$ is transcendental, when it's not even known yet that $\gamma$ is irrational (see the link you provided). – mathmandan Jan 04 '15 at 19:48
0

You can notice that there is O(n^(1/2)) unique values in the set S = {⌊n/1⌋, ⌊n/2⌋, ..., ⌊n/(n-1)⌋, ⌊n/n⌋}. Therefore you can calculate the function in O(n^(1/2))

Also since this function is asymmetric, you can even calculate x2 faster by using this formula: D(n) = Σ(x=1->u)(⌊n/x⌋) - u^2 for u = ⌊n^(1/2)⌋

Even more complex but faster: using the method that Richard Sladkey described in this paper you can calculate the function in O(n^(1/3))

  • Please provide additional details in your answer. As it's currently written, it's hard to understand your solution. – Community Aug 26 '21 at 21:41