Digital Signature
How many integers 0 <= n < 10^18 satisfy S(n) = S(137n), where S(k) denotes the digit sum of k?
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 , then .
Proof. For any non-negative integer , (since ). Therefore implies . Since , this gives , hence .
Theorem (Digit DP Recurrence). Define as the number of ways to choose digits at positions (from least significant to most significant) such that:
- is the current carry in the multiplication by 137,
- is the accumulated difference from the already-processed positions.
Then the recurrence is: for each digit , compute where and . Then:
Base case: where is the digit sum of the carry .
The answer is .
Proof. Write . The multiplication produces digits that depend on the carry chain. At position , if the digit of is and the incoming carry from lower positions is , then the digit of at this position is and the outgoing carry is .
The contribution to from this position is , and the contribution to is . The accumulated difference updates by .
After processing all 18 digits of , the remaining carry forms additional upper digits of (since can have up to 20 digits). These upper digits have digit sum . The condition becomes , yielding the base case.
Lemma (State Space Bounds). The DP state space is bounded as follows:
- Position: .
- Carry: (since , giving ).
- Difference: (since each of 18 digits contributes at most ).
Total states: .
Proof. The carry bound: at the first position, . For subsequent positions, . By induction, the carry never exceeds 136.
The difference bound: each position changes by where . Over 18 positions, .
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: .
- Space: for the DP table.
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#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;
}
"""
Problem 290: Digital Signature
Count integers 0 <= n < 10^18 where S(n) = S(137*n).
Approach: Digit DP processing digits from least to most significant.
State: (carry, diff) where carry is from the 137*n multiplication and
diff = S(n) - S(137n) accumulated so far.
"""
def solve():
DIGITS = 18
MAX_CARRY = 137 # 0..136
DIFF_OFFSET = 162
DIFF_RANGE = 325
# dp[carry][diff+offset] = count
dp = [[0] * DIFF_RANGE for _ in range(MAX_CARRY)]
dp[0][DIFF_OFFSET] = 1
for pos in range(DIGITS):
ndp = [[0] * DIFF_RANGE for _ in range(MAX_CARRY)]
for carry in range(MAX_CARRY):
for di in range(DIFF_RANGE):
cnt = dp[carry][di]
if cnt == 0:
continue
for y in range(10):
val = 137 * y + carry
new_carry = val // 10
v = val % 10
new_di = di + (y - v)
if 0 <= new_di < DIFF_RANGE and new_carry < MAX_CARRY:
ndp[new_carry][new_di] += cnt
dp = ndp
# After processing all digits of n, remaining carry c gives additional
# upper digits of 137*n. We need diff = digit_sum(carry).
def digit_sum(x):
s = 0
while x > 0:
s += x % 10
x //= 10
return s
result = 0
for carry in range(MAX_CARRY):
ds = digit_sum(carry)
di = DIFF_OFFSET + ds
if 0 <= di < DIFF_RANGE:
result += dp[carry][di]
print(result)
if __name__ == "__main__":
solve()
# Optional visualization: distribution of digit sum differences