Digit Factorial Chains
Define f(n) as the sum of factorials of the digits of n. Starting from any n, repeatedly applying f eventually enters a cycle. Let L(n) be the number of distinct values visited before entering a cy...
Problem Statement
This archive keeps the full statement, math, and original media on the page.
Starting with one piece of integer-sized rectangle paper, two players make moves in turn.
A valid move consists of choosing one piece of paper and cutting it both horizontally and vertically, so that it becomes four pieces of smaller rectangle papers, all of which are integer-sized.
The player that does not have a valid move loses the game.
Let $C(w, h)$ be the number of winning moves for the first player, when the original paper has size $w \times h$. For example, $C(5,3)=4$, with the four winning moves shown below.

Also write $\displaystyle D(W, H) = \sum_{w = 2}^W\sum_{h = 2}^H C(w, h)$. You are given that $D(12, 123) = 327398$.
Find $D(123, 1234567)$.
Problem 933: Digit Factorial Chains
Mathematical Foundation
Definition. The digit factorial function is .
Theorem 1 (Orbit contraction). For all , we have . Consequently, every orbit of eventually enters the interval .
Proof. A -digit number satisfies . Since each digit is at most 9, we have . For : (verified: ). Hence for all .
For : . Since every orbit eventually reaches a value , and , all subsequent iterates remain below . Within , the orbit must eventually revisit a value (by the pigeonhole principle), entering a cycle.
Theorem 2 (Complete cycle classification). The digit factorial function in base 10 has exactly the following attractors:
- Fixed points: , , , .
- 2-cycles: and .
- 3-cycle: .
Proof. This is verified by exhaustive computation: iterate from every starting value in and record the terminal cycle. By Theorem 1, every orbit enters this range, so no cycle outside it exists. The listed cycles are confirmed by direct evaluation:
- , , , .
- , .
- , , .
Lemma 1 (Memoization correctness). If we store for each visited value , then for any whose orbit passes through , we can compute .
Proof. The orbit is deterministic ( is a function), so the sequence of values from is uniquely determined. If is the first value in the orbit of for which is already known, then the total distinct values from equal the new values before reaching plus the distinct values from onward.
Editorial
Define f(n) = sum of factorials of digits of n. Starting from any n, repeatedly apply f to form a chain until a value repeats. Let L(n) be the number of distinct values in this chain. Compute sum_{n=1}^{N} L(n). Key observations:. We precompute factorials. We then f(n): sum of digit factorials. Finally, mark cycle members with their cycle contribution.
Pseudocode
Precompute factorials
f(n): sum of digit factorials
Memoization table: L[m] = chain length from m
Mark cycle members with their cycle contribution
(Fixed points have L = 1; 2-cycle members have L = 2; 3-cycle members have L = 3)
for n from 1 to N
if n in L
Follow orbit, recording path
while current not in L and current not in path
if current in L
Backfill from end of path
else
current is in path: found a new cycle
Complexity Analysis
- Time: where is the average chain length before hitting a cached value. Since orbits contract rapidly (Theorem 1), is bounded by a constant (at most steps to enter a cycle from any starting point below ). With memoization, amortized cost is .
- Space: where is the bound from Theorem 1. In practice, for the memoization 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 FACT[]={1,1,2,6,24,120,720,5040,40320,362880};
int dfs(int n){int s=0;while(n){s+=FACT[n%10];n/=10;}return s;}
int main(){
const int N=1000000;
vector<int> L(N+1,0);
for(int n=1;n<=N;n++){
unordered_set<int> seen;
int cur=n;
while(!seen.count(cur)){seen.insert(cur);cur=dfs(cur);}
L[n]=seen.size();
}
long long ans=0;
for(int i=1;i<=N;i++) ans+=L[i];
cout<<ans<<endl;
return 0;
}
"""
Problem 933: Digit Factorial Chains
Define f(n) = sum of factorials of digits of n. Starting from any n,
repeatedly apply f to form a chain until a value repeats. Let L(n) be
the number of distinct values in this chain. Compute sum_{n=1}^{N} L(n).
Key observations:
- For any n, f(n) <= 9! * digits(n) = 362880 * 7 = 2540160 for n <= 10^7.
- Once the chain enters a cycle, all cycle members have the same L.
- Pre-computing chain lengths for all values up to 2540160 allows O(1) lookup.
Methods:
- digit_fact_sum: Compute f(n).
- solve_memoized: Full DP approach with cycle detection for large N.
- chain_length_brute: Simple set-based chain length for small n.
Complexity: O(2540160) precomputation + O(N) for final summation.
"""
from collections import Counter
FACT = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
# Core: digit factorial sum
def digit_fact_sum(n):
"""Sum of factorials of digits of n."""
s = 0
while n > 0:
s += FACT[n % 10]
n //= 10
return s
def chain_length_brute(n):
"""Compute L(n) by following the chain until a repeat."""
seen = set()
cur = n
while cur not in seen:
seen.add(cur)
cur = digit_fact_sum(cur)
return len(seen)
def solve_memoized(N=10**6):
"""Sum of L(n) for n=1..N using memoized chain lengths."""
LIMIT = 2540161
chain_len = [0] * LIMIT
computed = [False] * LIMIT
for start in range(1, LIMIT):
if computed[start]:
continue
path = []
visited = {}
cur = start
while cur not in visited and cur < LIMIT and not computed[cur]:
visited[cur] = len(path)
path.append(cur)
cur = digit_fact_sum(cur)
if cur < LIMIT and computed[cur]:
for i in range(len(path) - 1, -1, -1):
chain_len[path[i]] = len(path) - i + chain_len[cur]
computed[path[i]] = True
elif cur in visited:
cycle_start = visited[cur]
cycle_len = len(path) - cycle_start
for i in range(cycle_start, len(path)):
chain_len[path[i]] = cycle_len
computed[path[i]] = True
for i in range(cycle_start - 1, -1, -1):
chain_len[path[i]] = len(path) - i
computed[path[i]] = True
total = 0
for n in range(1, N + 1):
if n < LIMIT:
total += chain_len[n] if chain_len[n] > 0 else 1
else:
nxt = digit_fact_sum(n)
total += 1 + (chain_len[nxt] if chain_len[nxt] > 0 else 1)
return total
# Verification
# Known chains:
# 169 -> 363601 -> 1454 -> 169 (cycle of 3)
assert chain_length_brute(169) == 3
# 1 -> 1 (cycle of 1)
assert chain_length_brute(1) == 1
# 2 -> 2 (cycle of 1)
assert chain_length_brute(2) == 1
# 145 -> 145 (cycle of 1: 1!+4!+5! = 1+24+120 = 145)
assert chain_length_brute(145) == 1
# 871 -> 45361 -> 871 (cycle of length 2... let's verify)
assert digit_fact_sum(871) == 45361
assert digit_fact_sum(45361) == 871
# Compute answer (small demo)
lengths = [chain_length_brute(n) for n in range(1, 1001)]
total_1000 = sum(lengths)
print(f"Sum of L(n) for n=1..1000: {total_1000}")