All Euler problems
Project Euler

Digital Signature

How many integers 0 <= n < 10^18 satisfy S(n) = S(137n), where S(k) denotes the digit sum of k?

Source sync Apr 19, 2026
Problem #0290
Level Level 14
Solved By 1,170
Languages C++, Python
Answer 20444710234716473
Length 325 words
dynamic_programmingdigit_dplinear_algebra

Problem Statement

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

How many integers \(0 \le n < 10^{18}\) have the property that the sum of the digits of \(n\) equals the sum of digits of \(137n\)?

Problem 290: Digital Signature

Mathematical Foundation

Theorem (Divisibility Constraint). If S(n)=S(137n)S(n) = S(137n), then 9n9 \mid n.

Proof. For any non-negative integer kk, S(k)k(mod9)S(k) \equiv k \pmod{9} (since 101(mod9)10 \equiv 1 \pmod{9}). Therefore S(n)=S(137n)S(n) = S(137n) implies n137n(mod9)n \equiv 137n \pmod{9}. Since 1372(mod9)137 \equiv 2 \pmod{9}, this gives n2n(mod9)n \equiv 2n \pmod{9}, hence n0(mod9)n \equiv 0 \pmod{9}. \quad\square

Theorem (Digit DP Recurrence). Define f(pos,c,d)f(\text{pos}, c, d) as the number of ways to choose digits at positions pos,pos+1,,17\text{pos}, \text{pos}+1, \ldots, 17 (from least significant to most significant) such that:

  • cc is the current carry in the multiplication by 137,
  • dd is the accumulated difference S(n)S(137n)S(n) - S(137n) from the already-processed positions.

Then the recurrence is: for each digit y{0,1,,9}y \in \{0, 1, \ldots, 9\}, compute 137y+c=10u+v137y + c = 10u + v where u=(137y+c)/10u = \lfloor(137y+c)/10\rfloor and v=(137y+c)mod10v = (137y+c) \bmod 10. Then:

f(pos,c,d)=y=09f(pos+1,u,d+yv).f(\text{pos}, c, d) = \sum_{y=0}^{9} f(\text{pos}+1, u, d + y - v).

Base case: f(18,c,d)=[d=S(c)]f(18, c, d) = [d = S(c)] where S(c)S(c) is the digit sum of the carry cc.

The answer is f(0,0,0)f(0, 0, 0).

Proof. Write n=i=017yi10in = \sum_{i=0}^{17} y_i \cdot 10^i. The multiplication 137n137n produces digits that depend on the carry chain. At position pos\text{pos}, if the digit of nn is yy and the incoming carry from lower positions is cc, then the digit of 137n137n at this position is v=(137y+c)mod10v = (137y + c) \bmod 10 and the outgoing carry is u=(137y+c)/10u = \lfloor(137y+c)/10\rfloor.

The contribution to S(n)S(n) from this position is yy, and the contribution to S(137n)S(137n) is vv. The accumulated difference updates by yvy - v.

After processing all 18 digits of nn, the remaining carry cc forms additional upper digits of 137n137n (since 137n137n can have up to 20 digits). These upper digits have digit sum S(c)S(c). The condition S(n)=S(137n)S(n) = S(137n) becomes daccumulated=S(c)d_{\text{accumulated}} = S(c), yielding the base case. \quad\square

Lemma (State Space Bounds). The DP state space is bounded as follows:

  • Position: 0pos180 \le \text{pos} \le 18.
  • Carry: 0c1360 \le c \le 136 (since max(1379+cprev)=1379+136=1369\max(137 \cdot 9 + c_{\text{prev}}) = 137 \cdot 9 + 136 = 1369, giving u136u \le 136).
  • Difference: 162d162-162 \le d \le 162 (since each of 18 digits contributes at most ±9\pm 9).

Total states: 19×137×325=846,17519 \times 137 \times 325 = 846{,}175.

Proof. The carry bound: at the first position, c=0c = 0. For subsequent positions, u=(137y+c)/10(1379+136)/10=1369/10=136u = \lfloor(137y + c)/10\rfloor \le \lfloor(137 \cdot 9 + 136)/10\rfloor = \lfloor 1369/10 \rfloor = 136. By induction, the carry never exceeds 136.

The difference bound: each position changes dd by yvy - v where yv9|y - v| \le 9. Over 18 positions, d162|d| \le 162. \quad\square

Editorial

Count integers 0 <= n < 10^18 where S(n) = S(137n). Approach: Digit DP processing digits from least to most significant. State: (carry, diff) where carry is from the 137n multiplication and diff = S(n) - S(137n) accumulated so far. We base case: after processing 18 digits. We then process positions 17 down to 0. Finally, this state will be reached from some (c_in, d_in) via digit y.

Pseudocode

dp[carry][diff_offset] where diff_offset = diff + 162
Base case: after processing 18 digits
Process positions 17 down to 0
This state will be reached from some (c_in, d_in) via digit y
Actually, iterate forward:
Forward formulation:

Complexity Analysis

  • Time: O(18×137×325×10)=O(81,022,500)8.1×107O(18 \times 137 \times 325 \times 10) = O(81{,}022{,}500) \approx 8.1 \times 10^7.
  • Space: O(137×325)=O(44,525)O(137 \times 325) = O(44{,}525) for the DP table.

Answer

20444710234716473\boxed{20444710234716473}

Code

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

C++ project_euler/problem_290/solution.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
    // Count 0 <= n < 10^18 with S(n) = S(137*n)
    // Digit DP: process digits from least significant to most significant
    // State: (position, carry, diff) where
    //   carry = carry from 137*n multiplication
    //   diff = S(n) - S(137*n) accumulated so far

    const int DIGITS = 18;
    const int MAX_CARRY = 137; // max carry: floor((137*9 + 136)/10) = 136, so 0..136
    const int DIFF_OFFSET = 162; // diff ranges from -162 to 162
    const int DIFF_RANGE = 325;

    // dp[carry][diff+offset] = count of numbers
    // Process digit by digit from position 0 to DIGITS-1

    vector<vector<long long>> dp(MAX_CARRY, vector<long long>(DIFF_RANGE, 0));
    dp[0][DIFF_OFFSET] = 1; // carry=0, diff=0

    for (int pos = 0; pos < DIGITS; pos++) {
        vector<vector<long long>> ndp(MAX_CARRY, vector<long long>(DIFF_RANGE, 0));
        for (int carry = 0; carry < MAX_CARRY; carry++) {
            for (int di = 0; di < DIFF_RANGE; di++) {
                if (dp[carry][di] == 0) continue;
                long long cnt = dp[carry][di];
                for (int y = 0; y <= 9; y++) {
                    int val = 137 * y + carry;
                    int new_carry = val / 10;
                    int v = val % 10;
                    int new_di = di + (y - v);
                    if (new_di >= 0 && new_di < DIFF_RANGE && new_carry < MAX_CARRY) {
                        ndp[new_carry][new_di] += cnt;
                    }
                }
            }
        }
        dp = ndp;
    }

    // After processing all digits of n, the remaining carry c represents
    // additional upper digits of 137*n. Their digit sum S(c) must equal
    // the accumulated diff: diff = S(carry).
    auto digitSum = [](int x) {
        int s = 0;
        while (x > 0) { s += x % 10; x /= 10; }
        return s;
    };

    long long ans = 0;
    for (int carry = 0; carry < MAX_CARRY; carry++) {
        int ds = digitSum(carry);
        int di = DIFF_OFFSET + ds;
        if (di >= 0 && di < DIFF_RANGE) {
            ans += dp[carry][di];
        }
    }
    cout << ans << endl;

    return 0;
}