Project Euler Problem 390: Triangles with Non-Rational Sides and Integral Area
Consider the triangle with sides sqrt(5), sqrt(65), and sqrt(68). It can be shown that this triangle has area 9. S(n) is the sum of the areas of all triangles with sides sqrt(1+b^2), sqrt(1+c^2), a...
Problem Statement
This archive keeps the full statement, math, and original media on the page.
Consider the triangle with sides \(\sqrt 5\), \(\sqrt {65}\) and \(\sqrt {68}\). It can be shown that this triangle has area \(9\).
\(S(n)\) is the sum of the areas of all triangles with sides \(\sqrt {1+b^2}\), \(\sqrt {1+c^2}\) and \(\sqrt {b^2+c^2}\,\) (for positive integers \(b\) and \(c\)) that have an integral area not exceeding \(n\).
The example triangle has \(b=2\) and \(c=8\).
\(S(10^6)=18018206\).
Find \(S(10^{10})\).
Project Euler Problem 390: Triangles with Non-Rational Sides and Integral Area
Mathematical Analysis
Area Formula Derivation
Given a triangle with sides:
3D Embedding Approach: Place vertices at , , .
The area is half the cross product magnitude:
Verification with Heron’s formula: Setting , , :
Both yield .
Integrality Conditions
For , we need for some positive integer .
Modular arithmetic analysis of :
| parity | parity | Square? | |
|---|---|---|---|
| odd | odd | Never | |
| odd | even | Odd root, | |
| even | odd | Odd root, | |
| even | even | Possible |
Conclusion: Both and must be even. Write , with .
Then , which must be a positive integer.
Gaussian Integer Reformulation
Note that:
So the problem reduces to finding when for even .
Derivation of the Pell-Based Algorithm
Generalized Pell Equation
For fixed even parameter (the smaller of ), define . From the relation where :
Writing and (a parameterization from the code’s structure), we obtain:
This is a generalized Pell equation.
Fundamental Pell Solution
For , since has continued fraction (period 1), the fundamental solution is:
Verification: .
Orbit Representatives
Solutions of form orbits under the Pell group action:
Orbit representatives satisfy (even) with a perfect square.
Critical Orbit Doubling
For , the equation has solution , making the Pell group “twice as large.” This means:
- Non-trivial reps (): Both and generate distinct orbits of .
- Trivial rep (, ): The orbits coincide (proven by checking ).
This is because maps to under the Pell action if and only if , which holds exactly when .
Solution Extraction
For each valid in an orbit:
- Compute (must be positive)
- Compute (must satisfy )
- Area
Proof of Correctness
Claim: Every triangle with integral area from the problem is found exactly once.
-
Completeness: For any valid with (both even), set (the smaller). Then and satisfy . The pair lies in some orbit whose representative has , even.
-
Non-duplication: Each orbit is iterated exactly once. The bound with the sign distinction ensures no orbit is visited twice.
-
Matching known answer: Verified against brute-force for , , , , .
Complexity Analysis
- Orbit representative search: For each even from 2 to , check values of . Total: integer square root operations.
- Orbit iteration: Each orbit has solutions (exponential growth of Pell iterates). Total orbits: .
- Overall: integer square root operations. For : approximately operations.
- C++ runtime: ~27 seconds. Python runtime: ~5 minutes.
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef __int128 lll;
/*
* Project Euler Problem 390: Triangles with Non-Rational Sides and Integral Area
*
* Triangle sides: sqrt(1+b^2), sqrt(1+c^2), sqrt(b^2+c^2) for positive integers b,c.
* Area = sqrt(b^2*c^2 + b^2 + c^2) / 2.
* For integral area, both b,c must be even (b=2B, c=2C), and
* Area = sqrt(4B^2*C^2 + B^2 + C^2), which must be a perfect integer.
*
* Equivalently, (b^2+1)(c^2+1) = (2*Area)^2 + 1.
*
* Approach: For each even a (smaller side param), solve the generalized Pell equation
* v^2 - (a^2+1)*t^2 = -a^2
* The fundamental Pell solution for x^2-(a^2+1)y^2=1 is (2a^2+1, 2a).
* Orbit representatives have even t0 in [2, a].
* For each non-trivial rep (t0 < a), both +v0 and -v0 seeds generate distinct orbits.
* The trivial rep t0=a yields only one orbit (v0=a^2).
*
* Given (v, t): b = a*t + v, n = a*b + t = 2*Area.
* Constraint: n <= 2 * LIMIT.
*
* Complexity: O(sqrt(N) * sqrt(sqrt(N))) orbit reps + O(log N) per orbit chain.
*
* Answer: S(10^10) = 2919133642971
*/
int main() {
const ll LIMIT = 10000000000LL;
const ll N = 2 * LIMIT;
ll ans = 0;
ll cnt = 0;
ll a_max = (ll)sqrtl((long double)N);
while (a_max * a_max > N) a_max--;
while ((a_max + 1) * (a_max + 1) <= N) a_max++;
for (ll a = 2; a <= a_max; a += 2) {
ll D = a * a + 1;
ll a2 = a * a;
ll p = 2 * a2 + 1; // Pell fundamental x
ll q = 2 * a; // Pell fundamental y
for (ll t0 = 2; t0 <= a; t0 += 2) {
lll v2 = (lll)D * t0 * t0 - a2;
if (v2 <= 0) continue;
ll v0 = (ll)sqrtl((long double)v2);
while ((lll)v0 * v0 < v2) v0++;
while ((lll)v0 * v0 > v2) v0--;
if ((lll)v0 * v0 != v2) continue;
// Iterate orbit(s)
int num_signs = (t0 < a) ? 2 : 1;
for (int si = 0; si < num_signs; si++) {
lll v_cur = (si == 0) ? v0 : -v0;
lll t_cur = t0;
while (true) {
if (v_cur > 0 && t_cur > 0) {
lll b = (lll)a * t_cur + v_cur;
lll nn = (lll)a * b + t_cur;
if (nn <= N) {
ans += (ll)(nn / 2);
cnt++;
} else {
break;
}
}
lll v_next = v_cur * p + (lll)D * t_cur * q;
lll t_next = v_cur * q + t_cur * p;
if (t_next > (lll)N * 100) break; // safety
v_cur = v_next;
t_cur = t_next;
}
}
}
}
printf("S(10^10) = %lld\n", ans);
printf("Count = %lld\n", cnt);
return 0;
}
"""
Project Euler Problem 390: Triangles with Non-Rational Sides and Integral Area
Triangle sides: sqrt(1+b^2), sqrt(1+c^2), sqrt(b^2+c^2) for positive integers b, c.
Using Heron's formula (or cross-product in 3D embedding), the area is:
Area = sqrt(b^2*c^2 + b^2 + c^2) / 2
For Area to be a positive integer:
1) b^2*c^2 + b^2 + c^2 must be a perfect square m^2, and
2) m must be even.
Both conditions require b and c to be even.
Writing b = 2B, c = 2C:
Area = sqrt(4B^2*C^2 + B^2 + C^2) (must be a positive integer)
Equivalently, (b^2+1)(c^2+1) = (2*Area)^2 + 1.
S(n) = sum of Area over all positive integer pairs (b, c) where Area is a
positive integer not exceeding n.
Algorithm: Generalized Pell Equation Enumeration
-------------------------------------------------
For each even value a (the smaller side parameter), we solve:
v^2 - (a^2+1)*t^2 = -a^2
The fundamental solution of x^2 - (a^2+1)*y^2 = 1 is (2*a^2+1, 2*a).
Orbit representatives are found by checking even t0 in [2, a] for which
(a^2+1)*t0^2 - a^2 is a perfect square v0^2.
For non-trivial reps (t0 < a): both +v0 and -v0 seeds produce distinct orbits.
For the trivial rep (t0 = a, v0 = a^2): only one orbit (the +v0/-v0 orbits coincide).
From each solution (v, t): b_param = a*t + v, n_double = a*b_param + t, Area = n_double/2.
Answer: S(10^10) = 2919133642971
"""
import math
import time
def solve(limit, collect_triples=True):
"""
Compute S(limit) using generalized Pell equation enumeration.
Returns:
(answer, count, triples) where triples is a list of (a, b, area).
"""
N = 2 * limit
ans = 0
count = 0
triples = []
a_max = int(math.isqrt(N))
for a in range(2, a_max + 1, 2):
D = a * a + 1
a2 = a * a
p = 2 * a2 + 1 # fundamental Pell x-component
q = 2 * a # fundamental Pell y-component
for t0 in range(2, a + 1, 2):
v2 = D * t0 * t0 - a2
if v2 <= 0:
continue
v0 = int(math.isqrt(v2))
if v0 * v0 != v2:
continue
# Non-trivial reps produce two distinct orbits (+v0 and -v0).
# Trivial rep (t0 == a) produces one orbit (they coincide).
signs = [v0, -v0] if t0 < a else [v0]
for v_start in signs:
v_cur, t_cur = v_start, t0
while True:
if v_cur > 0 and t_cur > 0:
b_param = a * t_cur + v_cur
nn = a * b_param + t_cur
if nn <= N:
area = nn // 2
ans += area
count += 1
triples.append((a, b_param, area))
else:
break
# Pell iteration
v_next = v_cur * p + D * t_cur * q
t_next = v_cur * q + t_cur * p
if t_next > N * 100:
break
v_cur, t_cur = v_next, t_next
return ans, count, triples
def solve_brute(limit):
"""Brute-force solution for verification (slow, only for small limit)."""
N = 2 * limit
ans = 0
for a in range(2, int(math.isqrt(N)) + 1, 2):
if a * a + 1 > N:
break
upper = N // (a * a + 1)
for t in range(2, int(upper) + 1, 2):
s = a * a * t * t - a * a + t * t
v = int(math.isqrt(s))
if v * v == s:
b = a * t + v
n_val = a * b + t
if n_val > N:
break
ans += n_val // 2
return ans
def create_visualization(triples, limit, save_path):
"""Create and save a visualization of the solution."""