Problem 411: Uphill Paths
View on Project EulerProject Euler Problem 411 Solution
EulerSolve provides an optimized solution for Project Euler Problem 411, Uphill Paths, with C++, Python, Java, and a step-by-step mathematical explanation.
Problem Summary For a given \(n\), define the stations $$P_i=\left(2^i \bmod n,\ 3^i \bmod n\right),\qquad 0 \le i \le 2n.$$ An uphill path from \((0,0)\) to \((n,n)\) uses only right and up moves, so the stations visited by such a path must appear in an order whose coordinates never decrease. Let \(S(n)\) be the maximum number of stations that can be visited by one uphill path. The program evaluates $$\sum_{k=1}^{30} S(k^5).$$ Mathematical Approach The implementation does not search over grid paths directly. Instead, it reduces the problem to a finite set of modular points and then solves an order problem on those points. 1) Reduce the Station Sequence to a Finite Prefix Write $$n = 2^{\alpha} 3^{\beta} m,\qquad \gcd(m,6)=1.$$ Consider the \(x\)-coordinate \(x_i = 2^i \bmod n\). For every \(i \ge \alpha\), the factor \(2^{\alpha}\) already divides \(2^i\), so modulo \(2^{\alpha}\) the value is fixed at \(0\). On the coprime part \(n / 2^{\alpha}\), the base \(2\) is invertible, hence the remaining behavior is purely periodic with period $$T_2 = \operatorname{ord}_{n / 2^{\alpha}}(2),$$ with the harmless convention \(T_2=1\) when \(n / 2^{\alpha}=1\). Thus the \(x\)-coordinate is eventually periodic after \(\alpha\) steps. Exactly the same argument applies to the \(y\)-coordinate \(y_i = 3^i \bmod n\)....
Detailed mathematical approach
Problem Summary
For a given \(n\), define the stations
$$P_i=\left(2^i \bmod n,\ 3^i \bmod n\right),\qquad 0 \le i \le 2n.$$
An uphill path from \((0,0)\) to \((n,n)\) uses only right and up moves, so the stations visited by such a path must appear in an order whose coordinates never decrease. Let \(S(n)\) be the maximum number of stations that can be visited by one uphill path. The program evaluates
$$\sum_{k=1}^{30} S(k^5).$$
Mathematical Approach
The implementation does not search over grid paths directly. Instead, it reduces the problem to a finite set of modular points and then solves an order problem on those points.
1) Reduce the Station Sequence to a Finite Prefix
Write
$$n = 2^{\alpha} 3^{\beta} m,\qquad \gcd(m,6)=1.$$
Consider the \(x\)-coordinate \(x_i = 2^i \bmod n\). For every \(i \ge \alpha\), the factor \(2^{\alpha}\) already divides \(2^i\), so modulo \(2^{\alpha}\) the value is fixed at \(0\). On the coprime part \(n / 2^{\alpha}\), the base \(2\) is invertible, hence the remaining behavior is purely periodic with period
$$T_2 = \operatorname{ord}_{n / 2^{\alpha}}(2),$$
with the harmless convention \(T_2=1\) when \(n / 2^{\alpha}=1\). Thus the \(x\)-coordinate is eventually periodic after \(\alpha\) steps.
Exactly the same argument applies to the \(y\)-coordinate \(y_i = 3^i \bmod n\). After \(\beta\) steps it is periodic with period
$$T_3 = \operatorname{ord}_{n / 3^{\beta}}(3),$$
again taking \(T_3=1\) when the modulus equals \(1\).
Therefore the pair sequence \((x_i,y_i)\) is periodic from
$$p = \max(\alpha,\beta)$$
onward, with common period
$$T = \operatorname{lcm}(T_2,T_3).$$
Every station with index \(i \ge p+T\) repeats one already seen in the block \(p, p+1, \dots, p+T-1\). Since the original problem only uses indices \(0 \le i \le 2n\), it is enough to generate
$$M = \min(2n+1,\ p+T)$$
points and then discard duplicates.
2) Convert Uphill Paths into a Longest Nondecreasing Subsequence
After deduplication, sort the distinct stations lexicographically by \(x\) and then by \(y\):
$$Q_1,\dots,Q_r,\qquad Q_j=(x_j,y_j),\qquad x_1 \le x_2 \le \cdots \le x_r.$$
If an uphill path visits stations \(Q_{j_1}, Q_{j_2}, \dots, Q_{j_t}\), then necessarily
$$x_{j_1} \le x_{j_2} \le \cdots \le x_{j_t},\qquad y_{j_1} \le y_{j_2} \le \cdots \le y_{j_t}.$$
Because the list is already sorted by \(x\), the first condition is automatic when we take an increasing index subsequence. So the entire problem becomes
$$S(n)=\operatorname{LNDS}(y_1,y_2,\dots,y_r),$$
where \(\operatorname{LNDS}\) denotes the length of the longest nondecreasing subsequence.
The word nondecreasing matters. Equal \(x\)-coordinates are allowed because a path can move vertically between two stations, and equal \(y\)-coordinates are allowed because it can move horizontally. That is why the implementation uses the patience-sorting variant based on the first tail strictly greater than the new \(y\)-value.
3) Worked Example: \(n=22\)
For \(n=22=2\cdot 11\), we have \(\alpha=1\) and \(\beta=0\). Hence
$$T_2=\operatorname{ord}_{11}(2)=10,\qquad T_3=\operatorname{ord}_{22}(3)=5,$$
so
$$p=1,\qquad T=\operatorname{lcm}(10,5)=10,\qquad M=\min(45,11)=11.$$
Thus all relevant stations already occur among the first \(11\) indices. After sorting and removing repeats, the \(y\)-sequence is
$$1,3,9,15,5,1,1,5,15,9,3.$$
Its longest nondecreasing subsequence has length \(5\), so
$$S(22)=5.$$
This matches the checkpoint used by the implementation. The same program also verifies \(S(123)=14\) and \(S(10000)=48\).
How the Code Works
The C++, Python, and Java implementations build a smallest-prime-factor table once up to \(30^5\). That table makes Euler's totient function and multiplicative orders fast to evaluate for every modulus \(n=k^5\).
For each \(k\in\{1,\dots,30\}\), the implementation forms \(n=k^5\), computes the preperiod length \(p\) and the common period \(T\), generates the first \(M\) stations, sorts and deduplicates them, and finally applies patience sorting with binary search to the \(y\)-coordinates. The Python entry point reuses the same compiled computation, while the Java version mirrors the same mathematics directly.
Complexity Analysis
For one modulus \(n\), let \(M=\min(2n+1,p+T)\), and let \(r\le M\) be the number of distinct stations after deduplication. Generating the modular points costs \(O(M)\). Sorting the distinct points costs \(O(r\log r)\), and the longest-nondecreasing-subsequence step also costs \(O(r\log r)\). Therefore one evaluation of \(S(n)\) runs in
$$O(r\log r)$$
time and uses \(O(r)\) memory.
Across all \(k \le 30\), the one-time prime-factor sieve up to \(30^5\) is near-linear and uses \(O(30^5)\) memory. After that precomputation, the point ordering work dominates.
References
- Problem page: https://projecteuler.net/problem=411
- Multiplicative order: Wikipedia — Multiplicative order
- Euler's totient function: Wikipedia — Euler's totient function
- Chinese remainder theorem: Wikipedia — Chinese remainder theorem
- Longest increasing subsequence and patience sorting: Wikipedia — Longest increasing subsequence
Mathematical approach · C++ solution · Python solution · Java solution
Previous: Problem 410 · All Project Euler solutions · Next: Problem 412