All Euler problems
Project Euler

Square on the Inside

Let ABCD be a quadrilateral whose vertices are lattice points lying on the coordinate axes: A(a, 0), B(0, b), C(-c, 0), D(0, -d) where 1 <= a, b, c, d <= m and a, b, c, d, m are integers. For m = 4...

Source sync Apr 19, 2026
Problem #0504
Level Level 08
Solved By 3,579
Languages C++, Python
Answer 694687
Length 259 words
number_theorygeometrygraph

Problem Statement

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

Let $ABCD$ be a quadrilateral whose vertices are lattice points lying on the coordinate axes as follows:

$A(a, 0)$, $B(0, b)$, $C(-c, 0)$, $D(0, -d)$, where $1 \le a, b, c, d \le m$ and $a, b, c, d, m$ are integers.

It can be shown that for $m = 4$ there are exactly $256$ valid ways to construct $ABCD$. Of these $256$ quadrilaterals, $42$ of them strictly contain a square number of lattice points.

How many quadrilaterals $ABCD$ strictly contain a square number of lattice points for $m = 100$?

Problem 504: Square on the Inside

Mathematical Analysis

Pick’s Theorem

For a simple polygon with vertices at lattice points:

A=i+b21A = i + \frac{b}{2} - 1

where AA is the area, ii is the number of interior lattice points, and bb is the number of boundary lattice points.

Area of the Quadrilateral

The quadrilateral has vertices A(a,0)A(a,0), B(0,b)B(0,b), C(c,0)C(-c,0), D(0,d)D(0,-d). Using the Shoelace formula:

Area=12(ab+bc+cd+da)=12(a+c)(b+d)\text{Area} = \frac{1}{2}(ab + bc + cd + da) = \frac{1}{2}(a+c)(b+d)

Wait — more carefully, the area of this kite-like shape is composed of 4 right triangles:

Area=12(ab+bc+cd+da)=(a+c)(b+d)2\text{Area} = \frac{1}{2}(ab + bc + cd + da) = \frac{(a+c)(b+d)}{2}

Boundary Points

The number of lattice points on a line segment from (x1,y1)(x_1, y_1) to (x2,y2)(x_2, y_2) (excluding one endpoint) is gcd(x2x1,y2y1)\gcd(|x_2 - x_1|, |y_2 - y_1|).

The four edges contribute:

  • ABAB: gcd(a,b)\gcd(a, b) points (excluding endpoints)
  • BCBC: gcd(c,b)\gcd(c, b) points
  • CDCD: gcd(c,d)\gcd(c, d) points
  • DADA: gcd(a,d)\gcd(a, d) points

Total boundary points (including 4 vertices):

b=gcd(a,b)+gcd(b,c)+gcd(c,d)+gcd(d,a)b = \gcd(a,b) + \gcd(b,c) + \gcd(c,d) + \gcd(d,a)

Wait — each edge from vertex to vertex has gcd+1\gcd + 1 lattice points (including both endpoints). So total boundary points = sum of edge points minus double-counted vertices:

b=gcd(a,b)+gcd(b,c)+gcd(c,d)+gcd(d,a)b = \gcd(a,b) + \gcd(b,c) + \gcd(c,d) + \gcd(d,a)

(Each edge contributes gcd1\gcd - 1 interior points + 2 endpoints. Sum = (gcd+1)4\sum(\gcd + 1) - 4 since each vertex counted twice = gcd\sum \gcd.)

Interior Points

From Pick’s Theorem:

i=Ab2+1=(a+c)(b+d)2gcd(a,b)+gcd(b,c)+gcd(c,d)+gcd(d,a)2+1i = A - \frac{b}{2} + 1 = \frac{(a+c)(b+d)}{2} - \frac{\gcd(a,b) + \gcd(b,c) + \gcd(c,d) + \gcd(d,a)}{2} + 1

We check whether ii is a perfect square.

Editorial

We precompute gcd(x, y) for all 1 <= x, y <= 100. We then precompute perfect squares up to max possible i. Finally, iterate over all (a, b, c, d) with 1 <= a, b, c, d <= 100.

Pseudocode

Precompute gcd(x, y) for all 1 <= x, y <= 100
Precompute perfect squares up to max possible i
For all (a, b, c, d) with 1 <= a, b, c, d <= 100:
Return counter
# Optimization

Complexity Analysis

  • Time: O(m4)O(m^4) with precomputed GCD table, which is 1004=108100^4 = 10^8 — feasible.
  • Space: O(m2)O(m^2) for GCD table.

Answer

694687\boxed{694687}

Code

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

C++ project_euler/problem_504/solution.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
    const int M = 100;

    // Precompute GCD table
    int g[M + 1][M + 1];
    for (int i = 0; i <= M; i++)
        for (int j = 0; j <= M; j++)
            g[i][j] = __gcd(i, j);

    // Precompute perfect squares
    // Max interior points: ((M+M)*(M+M))/2 + 1 = 2*M*M + 1 = 20001
    int max_i = 2 * M * M + 1;
    vector<bool> is_sq(max_i + 1, false);
    for (int k = 0; (long long)k * k <= max_i; k++)
        is_sq[k * k] = true;

    int count = 0;

    for (int a = 1; a <= M; a++) {
        for (int b = 1; b <= M; b++) {
            for (int c = 1; c <= M; c++) {
                for (int d = 1; d <= M; d++) {
                    int boundary = g[a][b] + g[b][c] + g[c][d] + g[d][a];
                    int twice_area = (a + c) * (b + d);
                    int twice_i = twice_area - boundary + 2;
                    // i must be integer, so twice_i must be even
                    if (twice_i % 2 != 0) continue;
                    int interior = twice_i / 2;
                    if (interior >= 0 && interior <= max_i && is_sq[interior])
                        count++;
                }
            }
        }
    }

    cout << count << endl;
    return 0;
}