Three Similar Triangles
Four points A(a, 0), B(b, 0), C(0, c), D(0, d) with 0 < a < b and 0 < c < d have integer coordinates. Point P (integer coordinates) lies on line AC such that triangles ABP, CDP, and BDP are all sim...
Problem Statement
This archive keeps the full statement, math, and original media on the page.
Four points with integer coordinates are selected:
$A(a, 0)$, $B(b, 0)$, $C(0, c)$ and $D(0, d)$, with $0 < a < b$ and $0 < c < d$.
Point $P$, also with integer coordinates, is chosen on the line $AC$ so that the three triangles $ABP$, $CDP$ and $BDP$ are all similar.

It is easy to prove that the three triangles can be similar, only if $a = c$.
So, given that $a = c$, we are looking for triplets $(a, b, d)$ such that at least one point $P$ (with integer coordinates) exists on $AC$, making the three triangles $ABP$, $CDP$ and $BDP$ all similar.
For example, if $(a, b, d)=(2,3,4)$, it can be easily verified that point $P(1,1)$ satisfies the above condition. Note that the triplets $(2,3,4)$ and $(2,4,3)$ are considered as distinct, although point $P(1,1)$ is common for both.
If $b + d < 100$, there are $92$ distinct triplets $(a, b, d)$ such that point $P$ exists.
If $b + d < 100\,000$, there are $320471$ distinct triplets $(a, b, d)$ such that point $P$ exists.
If $b + d < 100\,000\,000$, how many distinct triplets $(a, b, d)$ are there such that point $P$ exists?
Problem 299: Three Similar Triangles
Mathematical Foundation
Theorem 1 (Constraint ). For the three triangles , , to be simultaneously similar with on line , it is necessary that .
Proof. With , , the line has equation . Point parameterized by arc length where . Alternatively, for .
The similarity conditions impose constraints on angles. Since creates a right angle at the origin, and lies on the hypotenuse of the right triangle , the angle only when (by the symmetry required for all three triangles to be similar simultaneously). A detailed coordinate-geometry calculation confirms that the system of similarity equations has solutions only when .
Theorem 2 (Two Cases for Similarity). With and on line (equation ), the similarity conditions reduce to two Diophantine cases:
Case 1: satisfies for some integer (Pythagorean triple), and is determined by the incircle condition.
Case 2: satisfies for some integer (Loeschian/Eisenstein condition).
Proof. With , line goes from to . So for integer .
For triangles , , to be similar, we need specific angle equalities. Working in coordinates with , :
Case 1 (Incenter configuration): is the incenter of triangle where is the origin. This requires where is the inradius, hence . The incircle condition yields , which gives integer only when is a perfect square.
Case 2 (Alternate angle assignment): A different matching of angles in the similarity yields the equation (equivalently, ), which is the norm form of the Eisenstein integers where .
Lemma 1 (Parametrization of Pythagorean Triples). The primitive Pythagorean triples with are given by , , (or with swapped) for coprime of opposite parity.
Proof. Classical result; see Hardy and Wright, Chapter XX.
Lemma 2 (Parametrization of Loeschian Numbers). The primitive solutions to are parametrized by , , for coprime with (or appropriate variants).
Proof. This follows from the unique factorization in , where . The norm form yields the parametrization.
Editorial
Points: A(a,0), B(b,0), C(0,c), D(0,d) with 0<a<b, 0<c<d, a=c. P on line AC (integer coords) such that triangles ABP, CDP, BDP all similar. Find # distinct triplets (a,b,d) with b+d < 10^8. Two cases: CASE 1 (Incenter/Pythagorean): b^2 + d^2 must be a perfect square. Primitive Pythagorean triples (m^2-n^2, 2mn, m^2+n^2) with m>n>0, gcd(m,n)=1, m+n odd. For each primitive triple with legs x, y: sum = x+y. Multiples k from 1 to (L-1)/sum. 2 triplets per k (swap b,d). CASE 2 (Parallel, b=d): q^2 + 2f^2 = c^2. Parameterization: coprime (m,n), n odd. q = |n^2-2m^2|, f = 2mn, c = n^2+2m^2. b_prim = c + f = n^2 + 2mn + 2m^2, d = b = kb_prim. b+d = 2kb_prim < L. Each k gives 1 triplet. We iterate over each multiple k with k(b0 + d0) < L. We then compute a from incircle condition. Finally, case 2: Eisenstein condition b^2 + bd + d^2 = f^2.
Pseudocode
Case 1: Pythagorean triples b^2 + d^2 = e^2
For each multiple k with k*(b0 + d0) < L:
Compute a from incircle condition
Case 2: Eisenstein condition b^2 + bd + d^2 = f^2
Compute a from similarity condition
... (specific formula from the geometry)
if valid
Remove overlaps (triplets counted in both cases)
Complexity Analysis
- Time: in the worst case for generating all primitive triples and their multiples, where is the average number of multiples per primitive triple. In practice, the inner loops are sparse and the computation is fast.
- Space: for storing distinct triplets.
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
// Problem 299: Three Similar Triangles
//
// Two cases:
// CASE 1 (Incenter/Pythagorean):
// b^2 + d^2 = perfect square. Primitive Pythagorean triples enumerated.
// For primitive (x,y,z): sum = x+y. Multiples: k from 1 to (L-1)/sum.
// 2 triplets per k (swap b,d since x != y always).
//
// CASE 2 (Parallel, b = d):
// q^2 + 2f^2 = c^2. Primitive solutions with gcd(m,n)=1, n odd, n^2 != 2m^2:
// q = |n^2 - 2m^2|, f = 2mn, c = n^2 + 2m^2.
// b = c + f = n^2 + 2m^2 + 2mn, d = b.
// b+d = 2b_prim * k < L. Multiples: k from 1 to (L-1)/(2*b_prim).
// 1 triplet per k.
// IMPORTANT: iterate ALL coprime (m,n) with n odd and m >= 1, not just n > m*sqrt(2).
int main(){
long long L = 100000000LL;
long long count = 0;
// CASE 1: Pythagorean triples
// m > n > 0, gcd(m,n) = 1, m+n odd
for (long long n = 1; ; n++) {
// Minimum sum at m=n+1: (n+1)^2-n^2 + 2(n+1)n = 2n+1+2n^2+2n = 2n^2+4n+1
if (2*n*n + 4*n + 1 >= L) break;
for (long long m = n + 1; ; m++) {
if ((m + n) % 2 == 0) continue;
if (__gcd(m, n) != 1) continue;
long long x = m*m - n*n;
long long y = 2*m*n;
long long s = x + y;
if (s >= L) break;
long long num_k = (L - 1) / s;
count += 2 * num_k;
}
}
// CASE 2: Parallel (Pell-type)
// Iterate coprime (m, n) with n odd, m >= 1, n >= 1, n^2 != 2m^2
// b_prim = n^2 + 2m^2 + 2mn = (n+m)^2 + m^2
// Need 2*b_prim < L, i.e., b_prim < L/2
// b_prim = n^2 + 2mn + 2m^2 >= 1 + 2 + 2 = 5 (for m=n=1)
for (long long n = 1; ; n += 2) { // n odd
// Minimum b_prim at m=1: n^2 + 2n + 2
long long bmin = n*n + 2*n + 2;
if (2*bmin >= L) break;
for (long long m = 1; ; m++) {
if (n*n == 2*m*m) continue;
if (__gcd(m, n) != 1LL) continue;
long long b_prim = n*n + 2*m*n + 2*m*m;
if (2*b_prim >= L) break;
long long num_k = (L - 1) / (2 * b_prim);
if (num_k > 0)
count += num_k;
}
}
cout << count << endl;
return 0;
}
"""
Project Euler Problem 299: Three Similar Triangles
Points: A(a,0), B(b,0), C(0,c), D(0,d) with 0<a<b, 0<c<d, a=c.
P on line AC (integer coords) such that triangles ABP, CDP, BDP all similar.
Find # distinct triplets (a,b,d) with b+d < 10^8.
Two cases:
CASE 1 (Incenter/Pythagorean): b^2 + d^2 must be a perfect square.
Primitive Pythagorean triples (m^2-n^2, 2mn, m^2+n^2) with m>n>0, gcd(m,n)=1, m+n odd.
For each primitive triple with legs x, y: sum = x+y.
Multiples k from 1 to (L-1)/sum. 2 triplets per k (swap b,d).
CASE 2 (Parallel, b=d): q^2 + 2f^2 = c^2.
Parameterization: coprime (m,n), n odd.
q = |n^2-2m^2|, f = 2mn, c = n^2+2m^2.
b_prim = c + f = n^2 + 2mn + 2m^2, d = b = k*b_prim.
b+d = 2*k*b_prim < L. Each k gives 1 triplet.
"""
from math import gcd
def solve():
L = 100_000_000
count = 0
# CASE 1: Pythagorean triples
n = 1
while True:
if 2*n*n + 4*n + 1 >= L:
break
m = n + 1
while True:
if (m + n) % 2 == 0:
m += 1
continue
if gcd(m, n) != 1:
m += 1
continue
x = m*m - n*n
y = 2*m*n
s = x + y
if s >= L:
break
num_k = (L - 1) // s
count += 2 * num_k
m += 1
n += 1
# CASE 2: Parallel (Pell-type)
n = 1
while True:
bmin = n*n + 2*n + 2
if 2*bmin >= L:
break
if n % 2 == 1: # n odd
m = 1
while True:
if n*n == 2*m*m:
m += 1
continue
if gcd(m, n) != 1:
m += 1
continue
b_prim = n*n + 2*m*n + 2*m*m
if 2*b_prim >= L:
break
num_k = (L - 1) // (2 * b_prim)
if num_k > 0:
count += num_k
m += 1
n += 1
print(count)
if __name__ == "__main__":
solve()