All Euler problems
Project Euler

Fibonacci Paths

Alice walks on a lattice grid. From point (a,b) she can step to (a+x, b+y) provided sqrt(x^2+y^2) is a Fibonacci number (1, 2, 3, 5, 8, 13,...), with x >= 0 and y >= 0. Let F(W,H) be the number of...

Source sync Apr 19, 2026
Problem #0662
Level Level 15
Solved By 973
Languages C++, Python
Answer 860873428
Length 374 words
dynamic_programmingsequencemodular_arithmetic

Problem Statement

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

Alice walks on a lattice grid. She can step from one lattice point $A (a,b)$ to another $B (a+x,b+y)$ providing distance $AB = \sqrt{x^2+y^2}$ is a Fibonacci number $\{1,2,3,5,8,13,\ldots\}$ and $x\ge 0,$ $y\ge 0$.

In the lattice grid below Alice can step from the blue point to any of the red points.

Problem illustration

Let $F(W,H)$ be the number of paths Alice can take from $(0,0)$ to $(W,H)$.

You are given $F(3,4) = 278$ and $F(10,10) = 215846462$.

Find $F(10\,000,10\,000) \bmod 1\,000\,000\,007$.

Problem 662: Fibonacci Paths

Mathematical Foundation

Definition. A step (x,y)Z02(x, y) \in \mathbb{Z}_{\geq 0}^2 is valid if x2+y2=Fk\sqrt{x^2 + y^2} = F_k for some Fibonacci number FkF_k. Equivalently, (x,y)(x, y) is a non-negative integer solution to x2+y2=Fk2x^2 + y^2 = F_k^2.

Lemma 1 (Step Enumeration). For each Fibonacci number FkF_k, the set of valid steps is

Sk={(x,y)Z02:x2+y2=Fk2}.\mathcal{S}_k = \{(x, y) \in \mathbb{Z}_{\geq 0}^2 : x^2 + y^2 = F_k^2\}.

This always includes the axis-aligned steps (0,Fk)(0, F_k) and (Fk,0)(F_k, 0), plus all Pythagorean decompositions of Fk2F_k^2.

Proof. The pair (0,Fk)(0, F_k) satisfies 02+Fk2=Fk20^2 + F_k^2 = F_k^2 trivially, and similarly for (Fk,0)(F_k, 0). Any other solution (x,y)(x, y) with x,y>0x, y > 0 corresponds to a representation of Fk2F_k^2 as a sum of two positive squares, which exists if and only if Fk2F_k^2 has at least one prime factor 1(mod4)\equiv 1 \pmod{4} appearing to an odd power in the prime factorization, or FkF_k itself admits a Pythagorean triple. The enumeration for small Fibonacci numbers is: F1=1F_1 = 1: {(0,1),(1,0)}\{(0,1),(1,0)\}; F3=2F_3 = 2: {(0,2),(2,0)}\{(0,2),(2,0)\}; F4=3F_4 = 3: {(0,3),(3,0)}\{(0,3),(3,0)\}; F5=5F_5 = 5: {(0,5),(5,0),(3,4),(4,3)}\{(0,5),(5,0),(3,4),(4,3)\}; F6=8F_6 = 8: {(0,8),(8,0)}\{(0,8),(8,0)\}; F7=13F_7 = 13: {(0,13),(13,0),(5,12),(12,5)}\{(0,13),(13,0),(5,12),(12,5)\}. \square

Theorem 1 (Path Counting Recurrence). The number of paths F(x,y)F(x,y) from (0,0)(0,0) to (x,y)(x,y) satisfies:

F(x,y)=(dx,dy)SF(xdx,  ydy)F(x,y) = \sum_{(dx,dy) \in \mathcal{S}} F(x - dx,\; y - dy)

with F(0,0)=1F(0,0) = 1 and F(x,y)=0F(x,y) = 0 for x<0x < 0 or y<0y < 0, where S=kSk\mathcal{S} = \bigcup_k \mathcal{S}_k is the full step set.

Proof. Every path from (0,0)(0,0) to (x,y)(x,y) ends with a final step (dx,dy)S(dx, dy) \in \mathcal{S}. The number of paths whose final step is (dx,dy)(dx, dy) equals F(xdx,ydy)F(x - dx, y - dy), since the path up to the penultimate point is an arbitrary valid path from (0,0)(0,0) to (xdx,ydy)(x - dx, y - dy). Since each step has dx,dy0dx, dy \geq 0, the value x+yx + y strictly decreases along any path prefix, establishing a valid topological order for the recurrence. The base case F(0,0)=1F(0,0) = 1 counts the empty path. Summing over all possible final steps gives the recurrence. \square

Lemma 2 (Finiteness of Step Set). The number of relevant Fibonacci numbers for target (W,H)(W, H) is at most logφ(W2+H2)+O(1)\lceil \log_\varphi(\sqrt{W^2 + H^2}) \rceil + O(1), so S=O(logN)|\mathcal{S}| = O(\log N) where N=max(W,H)N = \max(W, H).

Proof. A step (dx,dy)(dx, dy) with dxWdx \leq W and dyHdy \leq H requires Fk=dx2+dy2W2+H2F_k = \sqrt{dx^2 + dy^2} \leq \sqrt{W^2 + H^2}. Since Fkφk/5F_k \sim \varphi^k / \sqrt{5}, the number of Fibonacci numbers up to W2+H2\sqrt{W^2 + H^2} is O(logφN)O(\log_\varphi N). Each Fibonacci number contributes O(1)O(1) steps on average (the number of representations as a sum of two squares is bounded by the divisor function). \square

Editorial

Count lattice paths from (0,0) to (W,H) where each step has length equal to a Fibonacci number. F(W,H) mod 10^9+7. Steps: all (x,y) with x,y >= 0 and x^2 + y^2 = fib_k^2.

Pseudocode

    S = enumerate_valid_steps(W, H) // all (dx,dy) with Fibonacci norm, dx<=W, dy<=H
    dp = 2D array of size (W+1) x (H+1), initialized to 0
    dp[0][0] = 1
    For x from 0 to W:
        For y from 0 to H:
            For each (dx, dy) in S:
                If x - dx >= 0 and y - dy >= 0 then
                    dp[x][y] += dp[x - dx][y - dy]
                    dp[x][y] %= mod
    Return dp[W][H]

Optimization. Use a rolling array: since the maximum dxdx in S\mathcal{S} is bounded by some DD, only the last DD rows of the DP table need to be stored.


## Complexity Analysis

- **Time:** $O(W \cdot H \cdot |\mathcal{S}|)$ where $|\mathcal{S}| = O(\log N)$. For $W = H = 10000$, this is approximately $10^8 \cdot O(\log 10000) \approx 4 \times 10^9$ operations.
- **Space:** $O(D \cdot H)$ with the rolling array, where $D$ is the maximum horizontal step size. Without optimization, $O(W \cdot H)$.

## Answer

$$
\boxed{860873428}
$$

Code

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

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

/*
 * Problem 662: Fibonacci Paths
 *
 * Count paths from (0,0) to (W,H) where each step has Fibonacci length.
 * F(W,H) mod 10^9+7.
 *
 * Step (dx,dy): dx,dy >= 0, dx^2+dy^2 = fib_k^2 for some Fibonacci fib_k.
 * DP: f[x][y] = sum over valid (dx,dy) of f[x-dx][y-dy].
 */

const int MOD = 1e9 + 7;

int main() {
    // Generate Fibonacci numbers
    vector<long long> fibs = {1, 2};
    while (fibs.back() < 20000) {
        fibs.push_back(fibs[fibs.size()-1] + fibs[fibs.size()-2]);
    }

    int W = 10, H = 10; // Small test case

    // Generate valid steps
    vector<pair<int,int>> steps;
    for (long long f : fibs) {
        if (f > max(W, H)) break;
        long long f2 = f * f;
        for (long long x = 0; x <= f; x++) {
            long long y2 = f2 - x * x;
            long long y = (long long)round(sqrt((double)y2));
            if (y * y == y2 && y >= 0 && x <= W && y <= H) {
                if (x > 0 || y > 0)
                    steps.push_back({(int)x, (int)y});
            }
        }
    }

    // Remove duplicates
    sort(steps.begin(), steps.end());
    steps.erase(unique(steps.begin(), steps.end()), steps.end());

    printf("Number of valid steps: %d\n", (int)steps.size());

    // DP
    vector<vector<long long>> dp(W + 1, vector<long long>(H + 1, 0));
    dp[0][0] = 1;

    for (int x = 0; x <= W; x++) {
        for (int y = 0; y <= H; y++) {
            if (dp[x][y] == 0) continue;
            for (auto [dx, dy] : steps) {
                int nx = x + dx, ny = y + dy;
                if (nx <= W && ny <= H) {
                    dp[nx][ny] = (dp[nx][ny] + dp[x][y]) % MOD;
                }
            }
        }
    }

    printf("F(%d,%d) = %lld\n", W, H, dp[W][H]);

    // Verify
    assert(dp[W][H] == 215846462);
    printf("Verification passed!\n");

    return 0;
}