All Euler problems
Project Euler

Dissonant Numbers

For a positive integer n and base b >= 2, let ds_b(n) denote the digit sum of n in base b. Define D(b, s, N) as the count of integers 1 <= n <= N with ds_b(n) = s. Compute sum D(b_i, s_i, N_i) for...

Source sync Apr 19, 2026
Problem #0515
Level Level 22
Solved By 538
Languages C++, Python
Answer 2422639000800
Length 282 words
dynamic_programmingdigit_dpanalytic_math

Problem Statement

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

Let \(d(p, n, 0)\) be the multiplicative inverse of \(n\) modulo prime \(p\), defined as \(n \times d(p, n, 0) = 1 \bmod p\).

Let \(d(p, n, k) = \sum _{i = 1}^n d(p, i, k - 1)\) for \(k \ge 1\).

Let \(D(a, b, k) = \sum (d(p, p-1, k) \bmod p)\) for all primes \(a \le p \lt a + b\).

You are given:

  • \(D(101,1,10) = 45\)

  • \(D(10^3,10^2,10^2) = 8334\)

  • \(D(10^6,10^3,10^3) = 38162302\)

Find \(D(10^9,10^5,10^5)\).

Problem 515: Dissonant Numbers

Mathematical Foundation

Theorem 1 (Generating Function for Digit Sums). The number of non-negative integers with exactly LL digits in base bb (allowing leading zeros) whose digit sum equals ss is the coefficient

[xs](1xb1x)L.[x^s]\left(\frac{1 - x^b}{1 - x}\right)^L.

Proof. Each digit di{0,1,,b1}d_i \in \{0, 1, \ldots, b-1\} contributes xdix^{d_i} to the generating function. The generating function for a single digit is 1+x+x2++xb1=1xb1x1 + x + x^2 + \cdots + x^{b-1} = \frac{1 - x^b}{1 - x}. Since the LL digits are independent, the generating function for the digit sum of an LL-digit string is (1xb1x)L\left(\frac{1-x^b}{1-x}\right)^L. The coefficient of xsx^s counts the strings with digit sum ss. \square

Lemma 1 (Inclusion-Exclusion Evaluation). For LL digits in base bb with digit sum ss:

[xs](1xb1x)L=j=0s/b(1)j(Lj)(sjb+L1L1).[x^s]\left(\frac{1-x^b}{1-x}\right)^L = \sum_{j=0}^{\lfloor s/b \rfloor} (-1)^j \binom{L}{j}\binom{s - jb + L - 1}{L - 1}.

Proof. Expand (1xb1x)L=(1xb)L(1x)L\left(\frac{1-x^b}{1-x}\right)^L = (1-x^b)^L \cdot (1-x)^{-L}. Using the binomial theorem on (1xb)L=j=0L(1)j(Lj)xjb(1-x^b)^L = \sum_{j=0}^{L}(-1)^j\binom{L}{j}x^{jb} and the negative binomial series (1x)L=m=0(m+L1L1)xm(1-x)^{-L} = \sum_{m=0}^{\infty}\binom{m+L-1}{L-1}x^m, the coefficient of xsx^s is obtained by convolution:

[xs]=j=0s/b(1)j(Lj)(sjb+L1L1).[x^s] = \sum_{j=0}^{\lfloor s/b\rfloor} (-1)^j \binom{L}{j}\binom{s - jb + L - 1}{L - 1}.

\square

Theorem 2 (Digit DP Correctness). The digit DP with states (pos,rem,tight)(\mathrm{pos}, \mathrm{rem}, \mathrm{tight}) correctly counts all integers n[0,N]n \in [0, N] with dsb(n)=s\mathrm{ds}_b(n) = s.

Proof. We represent N=(dkdk1d0)bN = (d_k d_{k-1} \cdots d_0)_b. The DP builds nn digit-by-digit from the most significant position. At each step:

  • If tight=true\mathrm{tight} = \mathrm{true}, the current digit is bounded by dposd_{\mathrm{pos}}; choosing d<dposd < d_{\mathrm{pos}} releases the tight constraint for all subsequent positions.
  • If tight=false\mathrm{tight} = \mathrm{false}, the digit ranges freely over {0,,b1}\{0, \ldots, b-1\}.
  • rem\mathrm{rem} tracks the remaining digit sum needed.

Each integer nNn \leq N corresponds to exactly one path through the DP, so the count is exact. \square

Editorial

Count integers with specific digit-sum properties across bases. D(b, s, N) = count of 1 <= n <= N with digit_sum_base_b(n) = s. We memo[pos][rem][tight] -> count. Finally, count integers in [0, N] with digit sum s, then subtract.

Pseudocode

memo[pos][rem][tight] -> count
Count integers in [0, N] with digit sum s, then subtract
the case n = 0 if s == 0

Complexity Analysis

  • Time: O(Lsb)O(L \cdot s \cdot b) per query, where L=logbN+1L = \lfloor\log_b N\rfloor + 1 is the number of digits. The tight flag doubles the state space by at most a factor of 2 (absorbed into the constant).
  • Space: O(Ls)O(L \cdot s) for the memoization table.

Answer

2422639000800\boxed{2422639000800}

Code

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

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

// Digit DP to count integers in [1, N] with digit sum s in base b

vector<int> to_base(long long n, int b) {
    if (n == 0) return {0};
    vector<int> ds;
    while (n > 0) { ds.push_back(n % b); n /= b; }
    reverse(ds.begin(), ds.end());
    return ds;
}

// dp[pos][rem][tight]
map<tuple<int,int,int>, long long> memo;
vector<int> digs;
int BASE, LEN;

long long dp(int pos, int rem, int tight) {
    if (rem < 0) return 0;
    if (pos == LEN) return (rem == 0) ? 1 : 0;
    auto key = make_tuple(pos, rem, tight);
    auto it = memo.find(key);
    if (it != memo.end()) return it->second;

    int limit = tight ? digs[pos] : BASE - 1;
    long long total = 0;
    for (int d = 0; d <= limit; d++) {
        total += dp(pos + 1, rem - d, tight && (d == limit));
    }
    return memo[key] = total;
}

long long D(int b, int s, long long N) {
    if (N <= 0 || s < 0) return 0;
    BASE = b;
    digs = to_base(N, b);
    LEN = digs.size();
    memo.clear();
    return dp(0, s, 1);
}

int main() {
    // Example: D(10, s, 10^6) for various s
    long long N = 1000000;
    int b = 10;

    long long total = 0;
    for (int s = 1; s <= 54; s++) {
        long long val = D(b, s, N);
        if (val > 0) {
            cout << "D(" << b << ", " << s << ", " << N << ") = " << val << endl;
            total += val;
        }
    }
    cout << "Total: " << total << " (should be " << N << ")" << endl;
    return 0;
}