Open Source · 7 Languages · 900+ Problems

Project Euler Solutions

Complete solutions in C++, Python & Java — with step-by-step mathematical explanations

All Problems

Problem 895: Gold & Silver Coin Game II

View on Project Euler

Project Euler Problem 895 Solution

EulerSolve provides an optimized solution for Project Euler Problem 895, Gold & Silver Coin Game II, with C++, Python, Java, and a step-by-step mathematical explanation.

Problem Summary Problem 895 asks for the value of \(G(9898)\) in the Gold & Silver Coin Game II, reduced modulo \(M=989898989\). The C++, Python, and Java implementations do not simulate game positions directly. Instead they evaluate an exact closed decomposition of \(G(n)\) consisting of a parity-sensitive kernel, a recurrence-defined coefficient sequence, and a short correction term. This reformulation is what makes the computation practical. Every ingredient can be generated in a single forward pass, and the only divisions are modular inverses, so the whole calculation stays inside \(\mathbb{Z}/M\mathbb{Z}\). Mathematical Approach Let \(u\) denote the modular inverse of \(3\), so \(3u\equiv 1\pmod M\). For \(n\ge 2\), the implementations compute \(G(n)\) from three pieces: a kernel sequence \(K(m)\), a coefficient sequence \(c_i\), and a parity-dependent prefactor \(B(n)\). Step 1: Isolate the kernel sequence The inner term depends only on the argument \(m\) and on its parity. Written in mathematical form, the implemented kernel is $K(m)=\begin{cases} 0, & m\le 0,\\ 1, & m=1,\\ 14\cdot 2^{m/2}u+6m-15 \pmod M, & m\ge 2,\ m\text{ even},\\ 20\cdot 2^{(m-1)/2}u+6m-15 \pmod M, & m\ge 3,\ m\text{ odd}. \end{cases}$ The power of \(2\) grows only with \(\lfloor m/2\rfloor\), while the coefficient in front of it switches from \(14\) to \(20\) when parity changes....

Detailed mathematical approach

Problem Summary

Problem 895 asks for the value of \(G(9898)\) in the Gold & Silver Coin Game II, reduced modulo \(M=989898989\). The C++, Python, and Java implementations do not simulate game positions directly. Instead they evaluate an exact closed decomposition of \(G(n)\) consisting of a parity-sensitive kernel, a recurrence-defined coefficient sequence, and a short correction term.

This reformulation is what makes the computation practical. Every ingredient can be generated in a single forward pass, and the only divisions are modular inverses, so the whole calculation stays inside \(\mathbb{Z}/M\mathbb{Z}\).

Mathematical Approach

Let \(u\) denote the modular inverse of \(3\), so \(3u\equiv 1\pmod M\). For \(n\ge 2\), the implementations compute \(G(n)\) from three pieces: a kernel sequence \(K(m)\), a coefficient sequence \(c_i\), and a parity-dependent prefactor \(B(n)\).

Step 1: Isolate the kernel sequence

The inner term depends only on the argument \(m\) and on its parity. Written in mathematical form, the implemented kernel is

$K(m)=\begin{cases} 0, & m\le 0,\\ 1, & m=1,\\ 14\cdot 2^{m/2}u+6m-15 \pmod M, & m\ge 2,\ m\text{ even},\\ 20\cdot 2^{(m-1)/2}u+6m-15 \pmod M, & m\ge 3,\ m\text{ odd}. \end{cases}$

The power of \(2\) grows only with \(\lfloor m/2\rfloor\), while the coefficient in front of it switches from \(14\) to \(20\) when parity changes. That even/odd split is one of the main structural features of the final formula.

Step 2: Build the coefficient sequence

The convolution weights form a second-order recurrence:

$c_0=1,\qquad c_1=10,$

$c_i\equiv \left((20i-10)c_{i-1}-(64i-64)c_{i-2}\right)i^{-1}\pmod M \qquad (i\ge 2).$

The first few values are

$1,\ 10,\ 118,\ 1540,\ 21286,\ \dots$

Because \(M\) is prime and every index \(i\) used in the computation satisfies \(1\le i<M\), the inverse \(i^{-1}\) always exists modulo \(M\).

Step 3: Package the recurrence with a generating function

If we define

$A(x)=\sum_{i\ge 0} c_i x^i,$

then the recurrence is equivalent to the differential equation

$\left(1-20x+64x^2\right)A'(x)=\left(10-64x\right)A(x),\qquad A(0)=1.$

Solving it gives

$A(x)=\frac{1}{\sqrt{1-20x+64x^2}}=\frac{1}{\sqrt{(1-4x)(1-16x)}}.$

This viewpoint explains why the recurrence weights naturally appear in a one-dimensional convolution: they are exactly the coefficients of a fixed algebraic generating function.

Step 4: Assemble the final formula for \(G(n)\)

The remaining term is a small parity-dependent correction:

$B(n)\equiv \begin{cases} 35\cdot 2^{n/2}u-6n-35u \pmod M, & n\text{ even},\\ 50\cdot 2^{(n-1)/2}u-6n-35u \pmod M, & n\text{ odd}. \end{cases}$

With that notation, the implemented identity is

$\boxed{G(n)\equiv B(n)+\sum_{i=0}^{\lfloor (n-1)/2\rfloor} c_i\,K(n-2i)\pmod M.}$

The shift by \(2\) means the parity of \(n\) is preserved throughout the sum. Even inputs only touch the even branch of the kernel, while odd inputs walk through the odd branch and finally terminate at \(K(1)=1\).

Step 5: Why the modular divisions are legitimate

The formula contains divisions by \(3\) and by the recurrence index \(i\). In modular arithmetic these are replaced by multiplicative inverses. Since \(M=989898989\) is prime, every nonzero residue has an inverse, so the computation is exact in the finite field \(\mathbb{Z}/M\mathbb{Z}\); nothing is being approximated numerically.

Worked Example: \(n=5\)

The recurrence gives

$c_2=\frac{(20\cdot 2-10)c_1-(64\cdot 2-64)c_0}{2}=\frac{30\cdot 10-64}{2}=118.$

Because \(n=5\) is odd, the prefactor is

$B(5)=50\cdot 2^2u-30-35u=165u-30\equiv 25\pmod M.$

The kernel values needed by the sum are

$K(5)=20\cdot 2^2u+15=80u+15,\qquad K(3)=20\cdot 2u+3=40u+3,\qquad K(1)=1.$

Therefore

$\begin{aligned} G(5)&\equiv B(5)+c_0K(5)+c_1K(3)+c_2K(1) \\ &\equiv 25+(80u+15)+10(40u+3)+118 \\ &\equiv 188+480u \\ &\equiv 188+160 \\ &\equiv 348 \pmod M. \end{aligned}$

This matches the known checkpoint used by the implementations.

How the Code Works

The C++, Python, and Java implementations all follow the same numerical plan. They first compute the inverse of \(3\), evaluate the parity-dependent prefactor \(B(n)\), and determine the limit \(\lfloor (n-1)/2\rfloor\). They then build the coefficient list \(c_0,c_1,\dots,c_{\lfloor (n-1)/2\rfloor}\) iteratively from the recurrence above.

After that, the implementation scans through the same index range once more, evaluates the kernel at \(n-2i\), multiplies by the stored coefficient \(c_i\), and accumulates the answer modulo \(M\). The C++ version obtains inverses with the extended Euclidean algorithm, while the Python and Java versions use fast modular exponentiation under the prime modulus. In every language, the algorithmic structure is identical.

Complexity Analysis

Let \(L=\lfloor (n-1)/2\rfloor\). Building the recurrence coefficients costs \(O(L)\) arithmetic steps, and the final convolution sum costs another \(O(L)\) steps. Because the modulus is fixed for the problem, this is linear time in \(n\). If one counts modular inverse computation explicitly, the running time is \(O(L\log M)\), which is still effectively linear here. The memory usage is \(O(L)\) because the coefficient list is stored for the final pass.

Footnotes and References

  1. Problem page: https://projecteuler.net/problem=895
  2. Recurrence relation: Wikipedia — Recurrence relation
  3. Generating function: Wikipedia — Generating function
  4. Cauchy product: Wikipedia — Cauchy product
  5. Modular multiplicative inverse: Wikipedia — Modular multiplicative inverse

Mathematical approach · C++ solution · Python solution · Java solution

Previous: Problem 894 · All Project Euler solutions · Next: Problem 896

Need help with a problem? Ask me! 💡
e
✦ Euler GLM 5.2
Hi! I'm Euler. Ask me anything about Project Euler problems, math concepts, or solution approaches! 🧮