All Euler problems
Project Euler

A Real Recursion

For every real number a > 1, define the sequence g_a by: g_a(x) = 1 for x < a, g_a(x) = g_a(x-1) + g_a(x-a) for x >= a. Let G(n) = g_(sqrt(n))(n). Given G(90) = 7564511, find sum G(p) (mod 10^9 + 7...

Source sync Apr 19, 2026
Problem #0517
Level Level 22
Solved By 528
Languages C++, Python
Answer 581468882
Length 388 words
modular_arithmeticnumber_theorycombinatorics

Problem Statement

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

For every real number \(a > 1\) is given the sequence \(g_a\) by: \[g_a(x) = \begin {cases} 1 &\text { for } x < a \\ g_a(x - 1) + g_a(x - a) &\text { for } x \ge a \end {cases}\]

Let \(G(n) = g_{\sqrt {n}} (n)\). You are given \(G(90) = 7564511\).

Find \(\displaystyle \sum G(p)\) for \(p\) prime and \(10000000 < p < 10010000\)

Give your answer modulo \(1000000007\).

Problem 517: A Real Recursion

Mathematical Foundation

Theorem 1 (Combinatorial Interpretation). Let a=pa = \sqrt{p}. Then ga(n)g_a(n) counts the number of ways to express the “walk” from some starting value x0<ax_0 < a to nn using steps of size 11 and aa. Equivalently, if we take kk steps of size aa and mm steps of size 11, then ga(n)g_a(n) equals a sum of binomial coefficients:

G(p)=gp(p)=k=0K(nkk),G(p) = g_{\sqrt{p}}(p) = \sum_{k=0}^{K} \binom{n_k}{k},

where K=pK = \lfloor\sqrt{p}\rfloor and nkn_k depends on the number of large steps taken.

Proof. Starting from a value x0<ax_0 < a and reaching pp with kk jumps of size aa and mm jumps of size 11, we need x0+ka+m=px_0 + ka + m = p with 0x0<a0 \leq x_0 < a, i.e., m=pkax0m = p - ka - x_0 with 0x0<a0 \leq x_0 < a. Since ga(x)=1g_a(x) = 1 for all x<ax < a (the base case covers a continuous interval), the starting point x0x_0 is implicitly determined. For integer steps, m+km + k total steps are taken, and we choose the positions of the kk large steps among the m+km + k steps. The number of such arrangements is (m+kk)\binom{m+k}{k}.

More precisely, letting a=pa = \sqrt{p}, the recursion unfolds to:

ga(p)=k=0p/a(pkak)g_a(p) = \sum_{k=0}^{\lfloor p/a \rfloor} \binom{p - \lceil ka \rceil}{k}

where the upper index tracks the number of steps of size aa, and ka\lceil ka \rceil accounts for the minimum value consumed by kk large steps to stay within the base-case region. Since a=pa = \sqrt{p}, the maximum kk is p\lfloor\sqrt{p}\rfloor. The exact value of nkn_k is p1k(p1)p - 1 - \lfloor k(\sqrt{p} - 1)\rfloor or a closely related expression depending on the precise unfolding. \square

Lemma 1 (Modular Binomial Computation). For a prime modulus qq, the binomial coefficient (nk)modq\binom{n}{k} \bmod q can be computed in O(1)O(1) time (after O(n)O(n) preprocessing of factorials and inverse factorials) via

(nk)n!(k!)1((nk)!)1(modq).\binom{n}{k} \equiv n! \cdot (k!)^{-1} \cdot ((n-k)!)^{-1} \pmod{q}.

Proof. Since qq is prime, Z/qZ\mathbb{Z}/q\mathbb{Z} is a field, so every nonzero element has a multiplicative inverse. Precompute i!modqi! \bmod q and (i!)1modq(i!)^{-1} \bmod q for i=0,1,,ni = 0, 1, \ldots, n using the recurrence i!=i(i1)!i! = i \cdot (i-1)! and Fermat’s little theorem for the inverse. Each binomial coefficient then requires O(1)O(1) multiplications. \square

Theorem 2 (Prime Sieving in Short Intervals). The primes in (107,107+104)(10^7, 10^7 + 10^4) can be found using a segmented sieve of Eratosthenes in O(107+104)O(\sqrt{10^7} + 10^4) time.

Proof. Sieve primes up to 107+104<3163\sqrt{10^7 + 10^4} < 3163. For each small prime pp, mark its multiples in the interval (107,107+104)(10^7, 10^7 + 10^4). The remaining unmarked entries are prime. \square

Editorial

For real a > 1: g_a(x) = 1 for x < a, g_a(x) = g_a(x-1) + g_a(x-a) for x >= a. G(n) = g_{sqrt(n)}(n). Find sum of G(p) mod 10^9+7 for primes p with 10^7 < p < 10^7+10^4. We sieve primes in (10^7, 10^7 + 10^4). We then precompute factorials mod MOD up to 10^7 + 10^4. Finally, compute G(p) for each prime p.

Pseudocode

Sieve primes in (10^7, 10^7 + 10^4)
Precompute factorials mod MOD up to 10^7 + 10^4
Compute G(p) for each prime p
for p in primes

Complexity Analysis

  • Time: Segmented sieve: O(107+104)O(\sqrt{10^7} + 10^4). Factorial precomputation: O(107)O(10^7). For each of the \sim620 primes, the inner sum has \sim3162 terms, each O(1)O(1): total O(620×3162)O(2×106)O(620 \times 3162) \approx O(2 \times 10^6). Overall: O(107)O(10^7).
  • Space: O(107)O(10^7) for factorial arrays.

Answer

581468882\boxed{581468882}

Code

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

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

const long long MOD = 1000000007;
const int MAXN = 10010001;

long long fac[MAXN], inv_fac[MAXN];

long long power(long long base, long long exp, long long mod) {
    long long result = 1;
    base %= mod;
    while (exp > 0) {
        if (exp & 1) result = result * base % mod;
        base = base * base % mod;
        exp >>= 1;
    }
    return result;
}

void precompute() {
    fac[0] = 1;
    for (int i = 1; i < MAXN; i++)
        fac[i] = fac[i-1] * i % MOD;
    inv_fac[MAXN-1] = power(fac[MAXN-1], MOD-2, MOD);
    for (int i = MAXN-2; i >= 0; i--)
        inv_fac[i] = inv_fac[i+1] * (i+1) % MOD;
}

long long C(int n, int k) {
    if (k < 0 || k > n) return 0;
    return fac[n] % MOD * inv_fac[k] % MOD * inv_fac[n-k] % MOD;
}

int main() {
    precompute();

    // Sieve primes in (10^7, 10^7 + 10^4)
    const int LO = 10000001, HI = 10010000;
    vector<bool> is_prime(HI + 1, true);
    is_prime[0] = is_prime[1] = false;
    for (int i = 2; (long long)i * i <= HI; i++) {
        if (is_prime[i]) {
            for (int j = i * i; j <= HI; j += i)
                is_prime[j] = false;
        }
    }

    long long ans = 0;

    for (int p = LO; p < HI; p++) {
        if (!is_prime[p]) continue;

        double a = sqrt((double)p);
        int K = (int)floor(a);  // floor(sqrt(p))

        // G(p) = sum_{k=0}^{K} C(n_k, k)
        // where n_k = p - 1 - floor(k * (a - 1))
        // This counts compositions reaching p from base region [0, a)
        long long gp = 0;
        for (int k = 0; k <= K; k++) {
            // Number of unit steps when k large jumps of size a are taken
            // The total distance covered is p from starting point in [0, a)
            // After k jumps of size a, remaining ~ p - k*a unit steps
            // The jumps can be interleaved: C(unit_steps + k - 1, k) or similar
            // More precisely: n_k = p - 1 - (int)(k * (a - 1))
            int nk = p - 1 - (int)floor(k * (a - 1.0));
            if (nk < k) break;
            gp = (gp + C(nk, k)) % MOD;
        }

        ans = (ans + gp) % MOD;
    }

    cout << ans << endl;
    return 0;
}