All Euler problems
Project Euler

Right Triangles with Integer Coordinates

Let O=(0,0), P=(x_1,y_1), Q=(x_2,y_2), with all coordinates integers in [0,50]. We ask for the number of right triangles OPQ.

Source sync Apr 19, 2026
Problem #0091
Level Level 03
Solved By 17,859
Languages C++, Python
Answer 14234
Length 484 words
geometrynumber_theorybrute_force

Problem Statement

This archive keeps the full statement, math, and original media on the page.

The points \(P(x_1, y_1)\) and \(Q(x_2, y_2)\) are plotted at integer co-ordinates and are joined to the origin, \(O(0,0)\), to form \(\triangle OPQ\).

PIC

There are exactly fourteen triangles containing a right angle that can be formed when each co-ordinate lies between \(0\) and \(2\) inclusive; that is, \(0 \le x_1, y_1, x_2, y_2 \le 2\).

PIC

Given that \(0 \le x_1, y_1, x_2, y_2 \le 50\), how many right triangles can be formed?

Problem 91: Right Triangles with Integer Coordinates

Counting Strategy

We count triangles by the location of the right angle.

1. Right angle at the origin

If the right angle is at OO, then

OPOQ=x1x2+y1y2=0.\overrightarrow{OP}\cdot \overrightarrow{OQ}=x_1x_2+y_1y_2=0.

Because all coordinates are nonnegative, this happens if and only if one point lies on the positive xx-axis and the other lies on the positive yy-axis. Hence this case contributes

5050=502.50\cdot 50 = 50^2.

2. Right angle on one of the axes, but not at the origin

Suppose the right angle is at P=(x,0)P=(x,0) with 1x501\le x\le 50. Since PO=(x,0)\overrightarrow{PO}=(-x,0) is horizontal, orthogonality forces PQ\overrightarrow{PQ} to be vertical, so Q=(x,y)Q=(x,y) with 1y501\le y\le 50. Therefore this contributes another

5050=502.50\cdot 50 = 50^2.

By symmetry, the same number of triangles have the right angle at a point (0,y)(0,y) on the yy-axis. Thus all axis cases together contribute

3502.3\cdot 50^2.

3. Right angle at an interior lattice point

Now let the right angle be at an interior point

P=(x,y),1x,y50.P=(x,y), \qquad 1\le x,y\le 50.

Write

g=gcd(x,y),x=ga,y=gb,g=\gcd(x,y), \qquad x=ga,\qquad y=gb,

so that gcd(a,b)=1\gcd(a,b)=1.

We want all lattice points Q=(X,Y)Q=(X,Y) such that OPQ=90\angle OPQ=90^\circ. This is equivalent to

POPQ=0,\overrightarrow{PO}\cdot \overrightarrow{PQ}=0,

that is,

(x,y)(Xx,Yy)=0(-x,-y)\cdot (X-x,Y-y)=0

or

x(Xx)+y(Yy)=0.x(X-x)+y(Y-y)=0.

Substituting x=gax=ga and y=gby=gb, we get

a(Xx)=b(Yy).a(X-x)=-b(Y-y).

Since gcd(a,b)=1\gcd(a,b)=1, divisibility implies that there exists tZt\in\mathbb Z such that

Xx=bt,Yy=at.X-x=bt,\qquad Y-y=-at.

Therefore every lattice point QQ giving a right angle at PP is of the form

Q=P+t(yg,xg),tZ{0}.Q=P+t\left(\frac{y}{g},-\frac{x}{g}\right), \qquad t\in\mathbb Z\setminus\{0\}.

So the primitive step along the line through PP perpendicular to OPOP is

(yg,xg).\left(\frac{y}{g},-\frac{x}{g}\right).

Positive direction

If t>0t>0, then

Q=(x+tyg,ytxg).Q=\left(x+t\frac{y}{g},\,y-t\frac{x}{g}\right).

To stay inside the square [0,50]2[0,50]^2, we need

x+tyg50,ytxg0.x+t\frac{y}{g}\le 50,\qquad y-t\frac{x}{g}\ge 0.

Hence

t(50x)gy,tygx.t\le \left\lfloor \frac{(50-x)g}{y}\right\rfloor, \qquad t\le \left\lfloor \frac{yg}{x}\right\rfloor.

So the number of valid positive steps is

min ⁣((50x)gy,ygx).\min\!\left(\left\lfloor \frac{(50-x)g}{y}\right\rfloor, \left\lfloor \frac{yg}{x}\right\rfloor\right).

Negative direction

If t<0t<0, write t=st=-s with s>0s>0. Then

Q=(xsyg,y+sxg).Q=\left(x-s\frac{y}{g},\,y+s\frac{x}{g}\right).

The bounds become

xsyg0,y+sxg50,x-s\frac{y}{g}\ge 0,\qquad y+s\frac{x}{g}\le 50,

so

sxgy,s(50y)gx.s\le \left\lfloor \frac{xg}{y}\right\rfloor, \qquad s\le \left\lfloor \frac{(50-y)g}{x}\right\rfloor.

Thus the number of valid negative steps is

min ⁣(xgy,(50y)gx).\min\!\left(\left\lfloor \frac{xg}{y}\right\rfloor, \left\lfloor \frac{(50-y)g}{x}\right\rfloor\right).

For a fixed interior point P=(x,y)P=(x,y), the number of triangles with right angle at PP is therefore

min ⁣((50x)gy,ygx)+min ⁣(xgy,(50y)gx).\min\!\left(\left\lfloor \frac{(50-x)g}{y}\right\rfloor, \left\lfloor \frac{yg}{x}\right\rfloor\right) + \min\!\left(\left\lfloor \frac{xg}{y}\right\rfloor, \left\lfloor \frac{(50-y)g}{x}\right\rfloor\right).

Summing over all interior lattice points gives the exact formula

T(N)=3N2+x=1Ny=1N[min ⁣((Nx)gcd(x,y)y,ygcd(x,y)x)+min ⁣(xgcd(x,y)y,(Ny)gcd(x,y)x)].T(N)=3N^2+\sum_{x=1}^{N}\sum_{y=1}^{N} \left[ \min\!\left(\left\lfloor \frac{(N-x)\gcd(x,y)}{y}\right\rfloor, \left\lfloor \frac{y\gcd(x,y)}{x}\right\rfloor\right) + \min\!\left(\left\lfloor \frac{x\gcd(x,y)}{y}\right\rfloor, \left\lfloor \frac{(N-y)\gcd(x,y)}{x}\right\rfloor\right) \right].

Editorial

The clean way to avoid overcounting is to classify triangles by the position of the right angle. The cases at the origin and on the axes are simple and contribute closed forms immediately, so the only real work is when the right angle sits at an interior lattice point P=(x,y)P=(x,y).

For such a point, the segment PQPQ must lie on the line through PP perpendicular to OPOP. Writing g=gcd(x,y)g=\gcd(x,y) gives the primitive lattice step on that perpendicular line, namely (y/g,x/g)(y/g,-x/g) up to sign. Every valid choice of QQ is obtained by moving along this primitive direction until the square boundary is hit. So the search space is constrained to just two one-dimensional walks from each interior point, and the number of admissible steps in each direction is exactly what the formula counts.

Pseudocode

Initialize the total with the three axis-based contributions $3N^2$.

For each interior lattice point $(x,y)$ with $1 \le x,y \le N$:
    Compute $g=\gcd(x,y)$
    Compute the primitive perpendicular step $(y/g,\;x/g)$

    Count how many forward steps keep the point inside the square
    Count how many backward steps keep the point inside the square

    Add both counts to the running total

Return the running total.

Correctness

Theorem. The method described above computes exactly the quantity requested in the problem statement.

Proof. The preceding analysis identifies the admissible objects and derives the formula, recurrence, or exhaustive search carried out by the algorithm. The computation evaluates exactly that specification, so every valid contribution is included once and no invalid contribution is counted. Therefore the returned value is the required answer. \square

Complexity Analysis

There are N2N^2 interior lattice points. Each point requires one gcd computation and O(1)O(1) arithmetic. Therefore:

  • Time: O(N2logN)O(N^2 \log N)
  • Space: O(1)O(1)

For N=50N=50, this is trivial to evaluate.

Answer

14234\boxed{14234}

Code

Each problem page includes the exact C++ and Python source files from the local archive.

C++ project_euler/problem_091/solution.cpp
#include <algorithm>
#include <cassert>
#include <iostream>
#include <numeric>

long long count_right_triangles(int n) {
    long long total = 3LL * n * n;

    for (int x = 1; x <= n; ++x) {
        for (int y = 1; y <= n; ++y) {
            const int g = std::gcd(x, y);
            const int step_x = y / g;
            const int step_y = x / g;

            total += std::min((n - x) / step_x, y / step_y);
            total += std::min(x / step_x, (n - y) / step_y);
        }
    }

    return total;
}

int main() {
    const long long answer = count_right_triangles(50);
    assert(answer == 14234);
    std::cout << answer << '\n';
    return 0;
}