All Euler problems
Project Euler

Sum of Remainders

Define S(n) as the sum of all remainders when n is divided by each positive integer up to n: S(n) = sum_(k=1)^n (n mod k) = sum_(k=1)^n (n - kfloor((n)/(k))) Compute S(N) for large N efficiently.

Source sync Apr 19, 2026
Problem #0900
Level Level 37
Solved By 176
Languages C++, Python
Answer 646900900
Length 385 words
modular_arithmeticanalytic_mathbrute_force

Problem Statement

This archive keeps the full statement, math, and original media on the page.

Two players play a game with two piles of stones. The players alternately take stones from one or both piles, subject to:

1.
the total number of stones taken is equal to the size of the smallest pile before the move;
2.
the move cannot take all the stones from a pile.

The player that is unable to move loses.

For example, if the piles are of sizes 2, 2 and 4 then there are four possible moves. \[ (2,2,4)\xrightarrow {(1,1,0)}(1,1,4)\quad (2,2,4)\xrightarrow {(1,0,1)}(1,2,3)\quad (2,2,4)\xrightarrow {(0,1,1)}(2,1,3)\quad (2,2,4)\xrightarrow {(0,0,2)}(2,2,2)\]

Let \(t(n)\) be the smallest nonnegative integer \(k\) such that the position with \(n\) piles of \(n\) stones and a single pile of \(n+k\) stones is losing for the first player assuming optimal play. For example, \(t(1) = t(2) = 0\) and \(t(3) = 2\).

Define \(\displaystyle S(N) = \sum _{n=1}^{2^N} t(n)\). You are given \(S(10) = 361522\).

Find \(S(10^4)\). Give your answer modulo \(900497239\).

Problem 900: Sum of Remainders

Mathematical Analysis

Theorem 1 (Remainder-to-Floor Reduction)

S(n)=n2k=1nknkS(n) = n^2 - \sum_{k=1}^{n} k\left\lfloor \frac{n}{k} \right\rfloor

Proof. By definition, nmodk=nkn/kn \bmod k = n - k\lfloor n/k \rfloor. Summing over k=1,,nk = 1, \ldots, n:

S(n)=k=1nnk=1nknk=n2k=1nknkS(n) = \sum_{k=1}^{n} n - \sum_{k=1}^{n} k\left\lfloor \frac{n}{k}\right\rfloor = n^2 - \sum_{k=1}^{n} k\left\lfloor \frac{n}{k}\right\rfloor \qquad \square

Theorem 2 (Floor Function Block Structure)

The function qn/qq \mapsto \lfloor n/q \rfloor takes at most 2n2\lfloor\sqrt{n}\rfloor distinct values. For each distinct value v=n/kv = \lfloor n/k \rfloor, the set of kk achieving this value forms a contiguous block [kmin,kmax][k_{\min}, k_{\max}] where:

kmin=nv+1+1,kmax=nvk_{\min} = \left\lfloor \frac{n}{v+1} \right\rfloor + 1, \qquad k_{\max} = \left\lfloor \frac{n}{v} \right\rfloor

Proof. For v1v \geq 1, n/k=v\lfloor n/k \rfloor = v iff vn/k<v+1v \leq n/k < v+1, i.e., n/(v+1)<kn/vn/(v+1) < k \leq n/v. The number of distinct values is bounded because either vnv \leq \sqrt{n} (at most n\sqrt{n} choices) or knk \leq \sqrt{n} (at most n\sqrt{n} choices), giving 2n\leq 2\sqrt{n} blocks total. \square

Lemma (Triangular Sum over a Block)

For a contiguous block [a,b][a, b] with constant n/k=v\lfloor n/k \rfloor = v:

k=abkv=v(ba+1)(a+b)2\sum_{k=a}^{b} k \cdot v = v \cdot \frac{(b-a+1)(a+b)}{2}

Derivation: The Dirichlet Hyperbola Method

We compute T(n)=k=1nkn/kT(n) = \sum_{k=1}^{n} k\lfloor n/k \rfloor by iterating over distinct values of n/k\lfloor n/k \rfloor.

Algorithm:

  1. Set T=0T = 0, k=1k = 1.
  2. While knk \leq n:
    • Let v=n/kv = \lfloor n/k \rfloor.
    • Let k=n/vk' = \lfloor n/v \rfloor (the last index in this block).
    • Add v(kk+1)(k+k)/2v \cdot (k' - k + 1)(k + k') / 2 to TT.
    • Set k=k+1k = k' + 1.
  3. Return S(n)=n2TS(n) = n^2 - T.

This runs in O(n)O(\sqrt{n}) iterations.

Concrete Numerical Examples

Example 1: S(10)S(10)

kk10modk10 \bmod k10/k\lfloor 10/k \rfloor
1010
205
313
422
502
641
731
821
911
1001

S(10)=0+0+1+2+0+4+3+2+1+0=13S(10) = 0+0+1+2+0+4+3+2+1+0 = 13

Verification via formula: T(10)=110+25+33+42+52+61+71+81+91+101=10+10+9+8+10+6+7+8+9+10=87T(10) = 1 \cdot 10 + 2 \cdot 5 + 3 \cdot 3 + 4 \cdot 2 + 5 \cdot 2 + 6 \cdot 1 + 7 \cdot 1 + 8 \cdot 1 + 9 \cdot 1 + 10 \cdot 1 = 10 + 10 + 9 + 8 + 10 + 6 + 7 + 8 + 9 + 10 = 87.

S(10)=10087=13S(10) = 100 - 87 = 13. Confirmed.

Example 2: S(100)S(100)

Using the O(n)O(\sqrt{n}) algorithm with 100=10\lfloor\sqrt{100}\rfloor = 10 blocks:

  • Block v=100v=100: k=1k=1, contributes 1100=1001 \cdot 100 = 100
  • Block v=50v=50: k=2k=2, contributes 250=1002 \cdot 50 = 100
  • Block v=1v=1: k=51..100k=51..100, contributes 1501512=37751 \cdot \frac{50 \cdot 151}{2} = 3775

S(100)=10000T(100)S(100) = 10000 - T(100). Direct computation yields S(100)=4049S(100) = 4049.

Verification Table

nnS(n)S(n) (brute force)S(n)S(n) (hyperbola)Match
100Yes
511Yes
101313Yes
205858Yes
50432432Yes
10040494049Yes

Alternative Approach: Connection to Divisor Sum

Note that k=1nn/k=k=1nd(k)\sum_{k=1}^{n} \lfloor n/k \rfloor = \sum_{k=1}^{n} d(k) is a classical identity (where the left side counts lattice points under the hyperbola xy=nxy = n). Our sum has an extra factor of kk, connecting it to the sum-of-divisors function:

k=1nknk=m=1nσ(m)\sum_{k=1}^{n} k\left\lfloor \frac{n}{k}\right\rfloor = \sum_{m=1}^{n} \sigma(m)

where σ(m)=dmd\sigma(m) = \sum_{d \mid m} d. This follows from writing n/k=#{m:km,1mn}\lfloor n/k \rfloor = \#\{m : k \mid m, 1 \leq m \leq n\} and swapping summation order.

Asymptotic Analysis

Using the known asymptotic m=1nσ(m)=π212n2+O(nlogn)\sum_{m=1}^{n} \sigma(m) = \frac{\pi^2}{12} n^2 + O(n \log n):

S(n)=n2π212n2+O(nlogn)=(1π212)n2+O(nlogn)0.17753n2S(n) = n^2 - \frac{\pi^2}{12} n^2 + O(n \log n) = \left(1 - \frac{\pi^2}{12}\right) n^2 + O(n \log n) \approx 0.17753 \cdot n^2

Complexity Analysis

MethodTimeSpace
Brute forceO(n)O(n)O(1)O(1)
Hyperbola methodO(n)O(\sqrt{n})O(1)O(1)

The hyperbola method enables computation for nn up to 101810^{18} in milliseconds.

Answer

646900900\boxed{646900900}

Code

Each problem page includes the exact C++ and Python source files from the local archive.

C++ project_euler/problem_900/solution.cpp
/*
 * Problem 900: Sum of Remainders
 *
 * Compute S(n) = sum_{k=1}^{n} (n mod k)
 *            = n^2 - sum_{k=1}^{n} k * floor(n/k)
 *
 * Uses the Dirichlet hyperbola method: floor(n/k) takes O(sqrt(n)) distinct
 * values, so we iterate over blocks of constant floor value.
 *
 * Complexity: O(sqrt(n)) time, O(1) space.
 */

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef __int128 lll;

// Brute force O(n) -- for verification
ll S_brute(ll n) {
    ll s = 0;
    for (ll k = 1; k <= n; k++)
        s += n % k;
    return s;
}

// O(sqrt(n)) via floor-block decomposition
ll S_hyperbola(ll n) {
    ll T = 0;
    ll k = 1;
    while (k <= n) {
        ll v = n / k;
        ll kp = n / v;  // last index in this block
        // Sum of k + (k+1) + ... + kp = (kp - k + 1) * (k + kp) / 2
        ll block_len = kp - k + 1;
        ll block_sum = block_len * (k + kp) / 2;
        T += v * block_sum;
        k = kp + 1;
    }
    return n * n - T;
}

// O(sqrt(n)) with 128-bit arithmetic for very large n
lll S_hyperbola_128(lll n) {
    lll T = 0;
    lll k = 1;
    while (k <= n) {
        lll v = n / k;
        lll kp = n / v;
        lll block_len = kp - k + 1;
        lll block_sum = block_len * (k + kp) / 2;
        T += v * block_sum;
        k = kp + 1;
    }
    return n * n - T;
}

void print_128(lll x) {
    if (x == 0) { cout << "0"; return; }
    if (x < 0) { cout << "-"; x = -x; }
    string s;
    while (x > 0) { s += char('0' + (int)(x % 10)); x /= 10; }
    reverse(s.begin(), s.end());
    cout << s;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    // Verification against brute force
    cout << "=== Verification ===" << endl;
    cout << setw(8) << "n" << setw(12) << "Brute" << setw(12) << "Hyperbola"
         << setw(8) << "Match" << endl;
    for (ll n : {1LL, 2LL, 5LL, 10LL, 20LL, 50LL, 100LL, 500LL, 1000LL}) {
        ll sb = S_brute(n);
        ll sh = S_hyperbola(n);
        cout << setw(8) << n << setw(12) << sb << setw(12) << sh
             << setw(8) << (sb == sh ? "OK" : "FAIL") << endl;
        assert(sb == sh);
    }

    // Large values
    cout << "\n=== Large computations ===" << endl;
    for (ll n : {1000000LL, 10000000LL, 100000000LL, 1000000000LL}) {
        ll val = S_hyperbola(n);
        double ratio = (double)val / ((double)n * n);
        cout << "S(" << n << ") = " << val
             << ", S/n^2 = " << fixed << setprecision(6) << ratio << endl;
    }

    cout << "\nTheoretical limit: 1 - pi^2/12 = "
         << fixed << setprecision(6) << 1.0 - M_PI * M_PI / 12.0 << endl;

    // Final answer
    ll ans = S_hyperbola(100000000LL);
    cout << "\nAnswer: S(10^8) = " << ans << endl;

    return 0;
}