Problem 865: Triplicate Numbers
View on Project EulerProject Euler Problem 865 Solution
EulerSolve provides an optimized solution for Project Euler Problem 865, Triplicate Numbers, with C++, Python, Java, and a step-by-step mathematical explanation.
Problem Summary For Problem 865, the implementation does not attempt to enumerate admissible numbers directly. Instead, it evaluates a counting function \(T(N)\) at \(N=10^4\) modulo the prime $M=998244353.$ The whole problem is encoded by three coupled sequences \(U_n\), \(V_n\), and \(E_n\). Their recurrences capture how valid structures of total size \(n\) are assembled from smaller ones, and the final answer is extracted from the \(E_n\) sequence. Mathematical Approach The C++, Python, and Java implementations use the same three recurrences: $V_1=1,\qquad V_n=9\sum_{i=0}^{n-1}U_iV_{n-1-i}\quad (n\ge 2),$ $U_n=V_{n-1}+9\sum_{i=0}^{n-1}U_iU_{n-1-i}\quad (n\ge 1),$ $E_0=1,\qquad E_n=10\sum_{i=0}^{n-1}U_iE_{n-1-i}\quad (n\ge 1).$ The target quantity is then $T(N)=\sum_{n=1}^{N}\frac{9E_n}{10}.$ Because every \(E_n\) with \(n\ge 1\) is a multiple of \(10\), this expression is an integer in exact arithmetic. Step 1: Read the Recurrences as Convolutions Each sum runs over all decompositions of \(n-1\) into $i+(n-1-i).$ That is exactly the Cauchy-product pattern for combining two smaller structures into one larger structure. The coefficients \(9\) and \(10\) are fixed multiplicative weights that come from the decimal choices built into the counting model. So the problem is reduced to computing convolution sums, not to scanning integers one by one....
Detailed mathematical approach
Problem Summary
For Problem 865, the implementation does not attempt to enumerate admissible numbers directly. Instead, it evaluates a counting function \(T(N)\) at \(N=10^4\) modulo the prime
$M=998244353.$
The whole problem is encoded by three coupled sequences \(U_n\), \(V_n\), and \(E_n\). Their recurrences capture how valid structures of total size \(n\) are assembled from smaller ones, and the final answer is extracted from the \(E_n\) sequence.
Mathematical Approach
The C++, Python, and Java implementations use the same three recurrences:
$V_1=1,\qquad V_n=9\sum_{i=0}^{n-1}U_iV_{n-1-i}\quad (n\ge 2),$
$U_n=V_{n-1}+9\sum_{i=0}^{n-1}U_iU_{n-1-i}\quad (n\ge 1),$
$E_0=1,\qquad E_n=10\sum_{i=0}^{n-1}U_iE_{n-1-i}\quad (n\ge 1).$
The target quantity is then
$T(N)=\sum_{n=1}^{N}\frac{9E_n}{10}.$
Because every \(E_n\) with \(n\ge 1\) is a multiple of \(10\), this expression is an integer in exact arithmetic.
Step 1: Read the Recurrences as Convolutions
Each sum runs over all decompositions of \(n-1\) into
$i+(n-1-i).$
That is exactly the Cauchy-product pattern for combining two smaller structures into one larger structure. The coefficients \(9\) and \(10\) are fixed multiplicative weights that come from the decimal choices built into the counting model. So the problem is reduced to computing convolution sums, not to scanning integers one by one.
This viewpoint matters because it immediately explains why a dynamic program works: every value at size \(n\) depends only on values from smaller sizes.
Step 2: Convert the Recurrences into Generating Functions
Introduce formal power series
$U(z)=\sum_{n\ge 0}U_nz^n,\qquad V(z)=\sum_{n\ge 1}V_nz^n,\qquad E(z)=\sum_{n\ge 0}E_nz^n.$
The convolution rules become
$V(z)=z+9z\,U(z)V(z),$
$U(z)=zV(z)+9z\,U(z)^2,$
$E(z)=1+10z\,U(z)E(z)=\frac{1}{1-10z\,U(z)}.$
The first identity shows that \(V\) is the basic seed \(z\) plus a recursive correction. The third identity is especially useful: once \(U(z)\) is known, \(E(z)\) is just a geometric-series type transform.
We can also eliminate \(V(z)\) via
$V(z)=\frac{z}{1-9z\,U(z)},$
which gives the cubic relation
$81z^2U(z)^3-18zU(z)^2+U(z)-z^2=0.$
The implementation does not solve this cubic symbolically, but it is a good consistency check on the recurrence system.
Step 3: Detect the Built-In Modulo-3 Structure
The first few exact values already reveal a rigid pattern:
$V_1=1,\qquad U_2=1,\qquad E_3=10,$
and then the nonzero terms continue at spacings of \(3\). This is not accidental.
Assume inductively that \(U_n\) can be nonzero only for \(n\equiv 2\pmod 3\) and \(V_n\) only for \(n\equiv 1\pmod 3\). In the recurrence for \(V_n\), a nonzero summand requires
$i\equiv 2\pmod 3,\qquad n-1-i\equiv 1\pmod 3,$
so \(n-1\equiv 0\pmod 3\), hence
$V_n\neq 0\implies n\equiv 1\pmod 3.$
In the recurrence for \(U_n\), the term \(V_{n-1}\) is nonzero only when \(n-1\equiv 1\pmod 3\), and the convolution term needs
$2+2\equiv 1\pmod 3,$
again forcing
$U_n\neq 0\implies n\equiv 2\pmod 3.$
Finally, for \(E_n\) a nonzero summand must pair a \(U\)-index congruent to \(2\) with an \(E\)-index congruent to \(0\), so
$E_n\neq 0\implies n\equiv 0\pmod 3.$
This residue-class behavior is the clearest structural fingerprint of the triplicate phenomenon in the recurrence system.
Step 4: Reindex to Compress the State Space
Because only every third term survives, it is natural to define
$A_k=U_{3k+2},\qquad B_k=V_{3k+1},\qquad C_k=E_{3k}.$
Then
$A_0=1,\qquad B_0=1,\qquad C_0=1,$
and for \(k\ge 1\) the recurrences simplify to
$B_k=9\sum_{a=0}^{k-1}A_aB_{k-1-a},$
$A_k=B_k+9\sum_{a=0}^{k-1}A_aA_{k-1-a},$
$C_k=10\sum_{a=0}^{k-1}A_aC_{k-1-a}.$
The target sum becomes
$T(N)=\frac{9}{10}\sum_{k=1}^{\lfloor N/3\rfloor}C_k.$
This reindexing is mathematically equivalent to the original system, but it makes the structure much easier to read: \(B\) feeds \(A\), and \(A\) feeds \(C\).
Step 5: Worked Example
Starting from \(A_0=B_0=C_0=1\), the next values are
$B_1=9A_0B_0=9,$
$A_1=B_1+9A_0A_0=9+9=18,$
$C_1=10A_0C_0=10.$
One more round gives
$B_2=9(A_0B_1+A_1B_0)=9(9+18)=243,$
$A_2=B_2+9(A_0A_1+A_1A_0)=243+9(18+18)=567,$
$C_2=10(A_0C_1+A_1C_0)=10(10+18)=280.$
Returning to the original indexing, this means
$E_3=10,\qquad E_6=280.$
Therefore
$T(6)=\frac{9}{10}(E_3+E_6)=\frac{9}{10}(10+280)=261,$
which matches the exact small-\(N\) check used by the implementation.
Step 6: Final Formula Used in the Modular Run
For the actual task the program computes
$T(10^4)\equiv 9\cdot 10^{-1}\sum_{n=1}^{10^4}E_n\pmod M,$
and because only indices divisible by \(3\) matter, this is the same as
$T(10^4)\equiv 9\cdot 10^{-1}\sum_{k=1}^{\lfloor 10^4/3\rfloor}C_k\pmod M.$
Since \(M\) is prime, the modular inverse is obtained from Fermat's little theorem:
$10^{-1}\equiv 10^{M-2}\pmod M.$
How the Code Works
The C++, Python, and Java implementations all follow the same pipeline. First, they allocate three arrays of length \(N+1\) for the sequences \(U\), \(V\), and \(E\), with the initial condition \(E_0=1\). They then sweep forward from \(n=1\) to \(n=N\).
In the first sweep, each \(n\) computes two convolution sums at once: one for the mixed product \(U_iV_{n-1-i}\), and one for the self-product \(U_iU_{n-1-i}\). Those two sums immediately produce \(V_n\) and \(U_n\). In the second sweep, the implementation computes \(E_n\) from the convolution of \(U\) and \(E\).
After all \(E_n\) values are known, the program accumulates
$\sum_{n=1}^{N}E_n$
and multiplies by \(9\cdot 10^{-1}\bmod M\). The C++ implementation also performs exact small-\(N\) consistency checks before the modular evaluation, including the benchmark
$T(6)=261$
and a larger exact value at \(N=30\). That is a good safeguard against recurrence or indexing mistakes.
Complexity Analysis
Let \(N\) be the requested size limit. The first phase computes two length-\(n\) convolutions for each \(n\), and the second phase computes one more length-\(n\) convolution. Therefore the total work is proportional to
$\sum_{n=1}^{N} n = O(N^2).$
More concretely, the algorithm performs about three triangular convolution passes, so the constant factor is moderate but the asymptotic order remains quadratic. The memory usage is \(O(N)\), because only the three one-dimensional arrays must be stored.