All Euler problems
Project Euler

Digit Sum Division

For a positive integer n, let d(n) be the sum of its decimal digits. Define F(N)=sum_(n=1)^N(n)/(d(n)). The given checks are: F(10)=19, F(123)approx 1.187764610390mathrm e3, F(12345)approx 4.855801...

Source sync Apr 19, 2026
Problem #0776
Level Level 19
Solved By 651
Languages C++, Python
Answer 9.627509725002e33
Length 645 words
linear_algebradynamic_programmingdigit_dp

Problem Statement

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

For a positive integer \(n\), \(d(n)\) is defined to be the sum of the digits of \(n\). For example, \(d(12345)=15\).

Let \(\displaystyle F(N)=\sum _{n=1}^N \frac n{d(n)}\).

You are given \(F(10)=19\), \(F(123)\approx 1.187764610390e3\) and \(F(12345)\approx 4.855801996238e6\).

Find \(F(1234567890123456789)\). Write your answer in scientific notation rounded to twelve significant digits after the decimal point. Use a lowercase e to separate the mantissa and the exponent.

Problem 776: Digit Sum Division

1. Group by the Digit Sum

For each s >= 1, define

Ts(N)=1nNd(n)=sn.T_s(N)=\sum_{\substack{1 \le n \le N \\ d(n)=s}} n.

Then

F(N)=s1Ts(N)s.F(N)=\sum_{s \ge 1}\frac{T_s(N)}{s}.

If N has L decimal digits, then d(n) <= 9L. For our target,

L=19,9L=171.L=19,\qquad 9L=171.

So it is enough to know T_s(N) for 1 <= s <= 171.

2. Suffix DP

Fix a nonnegative integer r.

  • Let C[r][s] be the number of r-digit strings (leading zeros allowed) whose digits sum to s.
  • Let S[r][s] be the sum of the numeric values of those r-digit strings.

For the empty suffix:

C[0][0]=1,S[0][0]=0.C[0][0]=1,\qquad S[0][0]=0.

For r >= 1, choose the first digit x of the suffix. The remaining r-1 digits must sum to s-x, so:

C[r][s]=x=09C[r1][sx],C[r][s]=\sum_{x=0}^{9} C[r-1][s-x],

where terms with negative index are omitted.

If a suffix starts with digit x, then its numeric value is

x10r1+u,x \cdot 10^{r-1} + u,

where u is the value of the remaining r-1 digits. Therefore

S[r][s]=x=09(x10r1C[r1][sx]+S[r1][sx]).S[r][s] = \sum_{x=0}^{9} \left( x \cdot 10^{r-1}\, C[r-1][s-x] + S[r-1][s-x] \right).

These tables are computed in O(L^2) states and a factor 10 for the choice of x.

3. Scan the Prefix of N

Write the decimal expansion of N as

a0a1aL1.a_0 a_1 \dots a_{L-1}.

Process the digits from left to right. Suppose we have already fixed a prefix:

  • its numeric value is P,
  • its digit sum is \sigma.

Now consider position i, with current limit digit a_i, and let r=L-1-i be the number of remaining digits.

For each smaller digit x < a_i, every number formed by choosing x here and then any legal suffix u of length r is

(10P+x)10r+u.(10P+x)\,10^r + u.

If the suffix has digit sum t, then the full number has digit sum \sigma + x + t, and the contribution of all such numbers to T_{\sigma+x+t}(N) is

((10P+x)10r)C[r][t]+S[r][t].\bigl((10P+x)10^r\bigr)\, C[r][t] + S[r][t].

After summing these contributions for every position and every x < a_i, we continue with the actual digit a_i, updating

P10P+ai,σσ+ai.P \leftarrow 10P + a_i,\qquad \sigma \leftarrow \sigma + a_i.

At the end, the exact number N itself is added to T_{d(N)}(N).

This gives every integer in [1,N] exactly once: it is counted at the first position where it is smaller than N, or as the final exact endpoint N.

4. Correctness

Lemma 1. C[r][s] equals the number of r-digit suffixes with digit sum s, and S[r][s] equals the sum of their numeric values.

Proof. The statement is true for r=0. For r>=1, partition the suffixes by their first digit x. The remaining r-1 digits then contribute exactly the recurrences above for both the count and the sum of values. By induction on r, the claim follows. \square

Lemma 2. During the prefix scan, the formula

((10P+x)10r)C[r][t]+S[r][t]\bigl((10P+x)10^r\bigr)\, C[r][t] + S[r][t]

is exactly the sum of all numbers whose processed prefix becomes 10P+x and whose remaining r digits have digit sum t.

Proof. There are C[r][t] such suffixes, and each contributes the common prefix term (10P+x)10^r. The suffix values themselves sum to S[r][t] by Lemma 1. Adding these two parts gives the stated formula. \square

Lemma 3. For every s >= 1, the algorithm computes T_s(N) exactly.

Proof. Every 1 <= n < N has a first position where its digit is smaller than the corresponding digit of N; at that position the algorithm counts it in exactly one branch x < a_i. The final endpoint N is added separately. By Lemma 2, each branch contributes the correct sum to the correct digit-sum bucket, so each T_s(N) is exact. \square

Theorem. The algorithm returns the correct value of F(N).

Proof. By Lemma 3, the algorithm computes all values T_s(N) exactly. Since

F(N)=s1Ts(N)s,F(N)=\sum_{s \ge 1}\frac{T_s(N)}{s},

summing these exact buckets divided by s gives the exact value of F(N). \square

5. Complexity Analysis

Let L be the number of decimal digits of N.

  • The DP tables contain O(L \cdot 9L) = O(L^2) states, each with at most 10 transitions.
  • The prefix scan also visits O(L^2) digit-sum states.

Hence:

  • Time: O(L^2).
  • Space: O(L^2).

For L=19, this is tiny.

Answer

The computation gives

9.627509725002e33\boxed{9.627509725002e33}

Code

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

C++ project_euler/problem_776/solution.cpp
#include <cassert>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

namespace {

const std::string TARGET = "1234567890123456789";
const std::string TARGET_ANSWER = "9.627509725002e33";

struct Tables {
    std::vector<std::vector<unsigned long long>> counts;
    std::vector<std::vector<long double>> totals;
    std::vector<long double> pow10;
};

Tables build_suffix_tables(int length) {
    const int max_sum = 9 * length;
    Tables tables{
        std::vector<std::vector<unsigned long long>>(
            length + 1, std::vector<unsigned long long>(max_sum + 1)
        ),
        std::vector<std::vector<long double>>(length + 1, std::vector<long double>(max_sum + 1)),
        std::vector<long double>(length + 1, 1.0L),
    };

    for (int i = 1; i <= length; ++i) {
        tables.pow10[i] = tables.pow10[i - 1] * 10.0L;
    }
    tables.counts[0][0] = 1;

    for (int digits = 1; digits <= length; ++digits) {
        const long double place = tables.pow10[digits - 1];
        for (int digit_sum = 0; digit_sum <= max_sum; ++digit_sum) {
            unsigned long long count = 0;
            long double total = 0.0L;
            for (int digit = 0; digit <= 9 && digit <= digit_sum; ++digit) {
                const unsigned long long prev_count =
                    tables.counts[digits - 1][digit_sum - digit];
                if (prev_count == 0) {
                    continue;
                }
                count += prev_count;
                total += static_cast<long double>(digit) * place * prev_count
                         + tables.totals[digits - 1][digit_sum - digit];
            }
            tables.counts[digits][digit_sum] = count;
            tables.totals[digits][digit_sum] = total;
        }
    }

    return tables;
}

std::vector<long double> digit_sum_weighted_totals(const std::string& limit) {
    const int length = static_cast<int>(limit.size());
    const int max_sum = 9 * length;
    const Tables tables = build_suffix_tables(length);

    std::vector<long double> by_sum(max_sum + 1, 0.0L);
    long double prefix_value = 0.0L;
    int prefix_sum = 0;

    for (int index = 0; index < length; ++index) {
        const int bound_digit = limit[index] - '0';
        const int remaining = length - 1 - index;
        const long double place = tables.pow10[remaining];

        for (int digit = 0; digit < bound_digit; ++digit) {
            const long double next_prefix = prefix_value * 10.0L + digit;
            for (int suffix_sum = 0; suffix_sum <= max_sum; ++suffix_sum) {
                const unsigned long long suffix_count = tables.counts[remaining][suffix_sum];
                if (suffix_count == 0) {
                    continue;
                }
                const int total_sum = prefix_sum + digit + suffix_sum;
                by_sum[total_sum] += next_prefix * place * suffix_count
                                   + tables.totals[remaining][suffix_sum];
            }
        }

        prefix_value = prefix_value * 10.0L + bound_digit;
        prefix_sum += bound_digit;
    }

    by_sum[prefix_sum] += prefix_value;
    return by_sum;
}

long double solve_value(const std::string& limit = TARGET) {
    const auto totals = digit_sum_weighted_totals(limit);
    long double answer = 0.0L;
    for (std::size_t digit_sum = 1; digit_sum < totals.size(); ++digit_sum) {
        answer += totals[digit_sum] / static_cast<long double>(digit_sum);
    }
    return answer;
}

long double brute_force(unsigned long long limit) {
    long double total = 0.0L;
    for (unsigned long long value = 1; value <= limit; ++value) {
        unsigned long long x = value;
        unsigned digit_sum = 0;
        while (x > 0) {
            digit_sum += static_cast<unsigned>(x % 10);
            x /= 10;
        }
        total += static_cast<long double>(value) / digit_sum;
    }
    return total;
}

std::string format_answer(long double value, int digits_after_decimal = 12) {
    std::ostringstream out;
    out << std::scientific << std::setprecision(digits_after_decimal) << value;
    const std::string text = out.str();
    const std::size_t split = text.find('e');
    const std::string mantissa = text.substr(0, split);
    const int exponent = std::stoi(text.substr(split + 1));
    return mantissa + "e" + std::to_string(exponent);
}

bool nearly_equal(long double a, long double b, long double eps) {
    return std::fabs(a - b) <= eps;
}

void self_test() {
    assert(nearly_equal(solve_value("10"), 19.0L, 1e-30L));
    assert(format_answer(solve_value("123")) == "1.187764610390e3");
    assert(format_answer(solve_value("12345")) == "4.855801996238e6");

    for (unsigned long long limit : {1ULL, 2ULL, 10ULL, 25ULL, 100ULL, 250ULL}) {
        assert(nearly_equal(solve_value(std::to_string(limit)), brute_force(limit), 1e-15L));
    }

    assert(format_answer(solve_value()) == TARGET_ANSWER);
}

}  // namespace

int main() {
    self_test();
    std::cout << format_answer(solve_value()) << '\n';
    return 0;
}