All Euler problems
Project Euler

Project Euler Problem 397 -- Triangle on Parabola

On the parabola y = x^2 / k (for a positive integer k), three points A(a, a^2/k), B(b, b^2/k), C(c, c^2/k) are chosen with integer x-coordinates satisfying 0 < a < b < c <= k. The area of triangle...

Source sync Apr 19, 2026
Problem #0397
Level Level 29
Solved By 323
Languages C++, Python
Answer 141630459461893728
Length 256 words
geometryalgebrabrute_force

Problem Statement

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

On the parabola \(y = x^2/k\), three points \(A(a, a^2/k)\), \(B(b, b^2/k)\) and \(C(c, c^2/k)\) are chosen.

Let \(F(K, X)\) be the number of the integer quadruplets \((k, a, b, c)\) such that at least one angle of the triangle \(ABC\) is \(45\)-degree, with \(1 \le k \le K\) and \(-X \le a < b < c \le X\).

For example, \(F(1, 10) = 41\) and \(F(10, 100) = 12492\).

Find \(F(10^6, 10^9)\).

Project Euler Problem 397 — Triangle on Parabola

Derivation of the Area Formula

Place three points on y=x2/ky = x^2/k with x-coordinates a<b<ca < b < c. Using the shoelace formula:

Area=12a ⁣(b2kc2k)+b ⁣(c2ka2k)+c ⁣(a2kb2k).\text{Area} = \tfrac{1}{2}\left| a\!\left(\tfrac{b^2}{k} - \tfrac{c^2}{k}\right) + b\!\left(\tfrac{c^2}{k} - \tfrac{a^2}{k}\right) + c\!\left(\tfrac{a^2}{k} - \tfrac{b^2}{k}\right) \right|.

Expanding:

=12ka(b2c2)+b(c2a2)+c(a2b2).= \frac{1}{2k}\left|a(b^2-c^2) + b(c^2-a^2) + c(a^2-b^2)\right|.

Factor the expression inside the absolute value:

a(b2c2)+b(c2a2)+c(a2b2)=(ba)(ca)(cb).a(b^2-c^2) + b(c^2-a^2) + c(a^2-b^2) = (b-a)(c-a)(c-b).

Hence

Area=(ba)(cb)(ca)2k.\boxed{\text{Area} = \frac{(b-a)(c-b)(c-a)}{2k}}.

(All three factors are positive since a<b<ca < b < c.)

Key Constraint

The area condition Areak\text{Area} \le k becomes

(ba)(cb)(ca)2k2.(b - a)(c - b)(c - a) \le 2k^2.

Counting Strategy

Let u=ba1u = b - a \ge 1 and v=cb1v = c - b \ge 1. Then ca=u+vc - a = u + v and we need

uv(u+v)2k2u \cdot v \cdot (u + v) \le 2k^2

with the additional constraint a1a \ge 1 and c=a+u+vkc = a + u + v \le k, so aa ranges from 11 to kuvk - u - v, giving kuvk - u - v valid values of aa (when u+vk1u + v \le k - 1).

Therefore

S(k)=u1,v1u+vk1uv(u+v)2k2(kuv).S(k) = \sum_{\substack{u \ge 1,\; v \ge 1 \\ u + v \le k - 1 \\ u\,v\,(u+v) \le 2k^2}} (k - u - v).

Algorithm (O(k) time)

For each fixed uu from 11 upward, find the maximum vv satisfying both constraints:

  1. Range constraint: vk1uv \le k - 1 - u
  2. Area constraint: uv(u+v)2k2u \cdot v \cdot (u + v) \le 2k^2

The area constraint uv(u+v)2k2u v(u+v) \le 2k^2 rearranges to uv2+u2v2k2u v^2 + u^2 v \le 2k^2, a quadratic in vv:

vu+u2+8k2/u2vmaxarea(u).v \le \frac{-u + \sqrt{u^2 + 8k^2/u}}{2} \eqqcolon v_{\max}^{\text{area}}(u).

Set vmax(u)=min ⁣(vmaxarea(u),  k1u)v_{\max}(u) = \min\!\bigl(\lfloor v_{\max}^{\text{area}}(u)\rfloor,\; k-1-u\bigr).

The inner sum telescopes:

v=1vmax(kuv)=vmax(ku)vmax(vmax+1)2.\sum_{v=1}^{v_{\max}} (k - u - v) = v_{\max}(k - u) - \frac{v_{\max}(v_{\max}+1)}{2}.

The outer loop over uu terminates once even v=1v = 1 violates the area constraint, i.e., when u(u+1)>2k2u(u+1) > 2k^2, giving umax2ku_{\max} \approx \sqrt{2}\,k.

Since umax=O(k)u_{\max} = O(k) and each iteration is O(1)O(1), the total time is O(k)O(k).

Sample Values

kkS(k)S(k)
1010120120
100100161,700161{,}700
1,0001{,}00027,955,49827{,}955{,}498
10410^47,343,965,8907{,}343{,}965{,}890
10510^51,749,913,169,7201{,}749{,}913{,}169{,}720
10610^6397,325,186,769,552397{,}325{,}186{,}769{,}552

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

Answer

141630459461893728\boxed{141630459461893728}

Complexity

  • Time: O(k)O(k) — single pass over uu with O(1)O(1) work per step.
  • Space: O(1)O(1).

Code

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

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

/*
 * Project Euler Problem 397 -- Triangle on Parabola
 *
 * On parabola y = x^2/k, points with integer x-coords a < b < c
 * (0 < a < b < c <= k) form a triangle with area = (b-a)(c-b)(c-a)/(2k).
 *
 * S(k) = # triples with area <= k, i.e. (b-a)(c-b)(c-a) <= 2k^2.
 *
 * Substituting u = b-a, v = c-b:
 *   u*v*(u+v) <= 2k^2, u >= 1, v >= 1, u+v <= k-1
 *   Each valid (u,v) contributes (k - u - v) triples.
 *
 * For each u, find max v via quadratic formula on u*v^2 + u^2*v <= 2k^2.
 */

typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;

// Find max v >= 1 such that u*v*(u+v) <= bound
ll max_v_for_u(ll u, ll bound) {
    // Check if v=1 works
    if (u * 1LL * (u + 1) > bound) return 0;

    // u*v^2 + u^2*v <= bound
    // v^2 + u*v - bound/u <= 0
    // v <= (-u + sqrt(u^2 + 4*bound/u)) / 2
    double disc = (double)u * u + 4.0 * (double)bound / u;
    ll v_max = (ll)((-u + sqrt(disc)) / 2.0);

    // Adjust for floating point errors using 128-bit arithmetic
    while (v_max >= 1 && (lll)u * v_max * (u + v_max) > bound) v_max--;
    while ((lll)u * (v_max + 1) * (u + v_max + 1) <= bound) v_max++;

    return max(v_max, 0LL);
}

ll S(ll k) {
    ll bound = 2LL * k * k;
    ll total = 0;

    for (ll u = 1; u <= k - 2; u++) {
        ll vm_area = max_v_for_u(u, bound);
        if (vm_area < 1) break;  // monotone: larger u won't work either

        ll vm_range = k - 1 - u;
        if (vm_range < 1) break;

        ll vm = min(vm_area, vm_range);

        // Sum_{v=1}^{vm} (k - u - v) = vm*(k-u) - vm*(vm+1)/2
        total += vm * (k - u) - vm * (vm + 1) / 2;
    }

    return total;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    // Verify small cases
    cout << "Small cases:" << endl;
    for (int k = 3; k <= 20; k++) {
        cout << "  S(" << k << ") = " << S(k) << endl;
    }

    // Compute moderate cases
    cout << endl;
    for (ll k : {100LL, 1000LL, 10000LL, 100000LL}) {
        auto t0 = chrono::high_resolution_clock::now();
        ll result = S(k);
        auto t1 = chrono::high_resolution_clock::now();
        double ms = chrono::duration<double, milli>(t1 - t0).count();
        cout << "S(" << k << ") = " << result << "  (" << ms << " ms)" << endl;
    }

    // Compute answer
    cout << endl << "Computing S(10^6)..." << endl;
    auto t0 = chrono::high_resolution_clock::now();
    ll answer = S(1000000LL);
    auto t1 = chrono::high_resolution_clock::now();
    double sec = chrono::duration<double>(t1 - t0).count();

    cout << "S(10^6) = " << answer << "  (" << sec << " s)" << endl;
    cout << endl << "Answer: " << answer << endl;

    return 0;
}