All Euler problems
Project Euler

Optimum Polynomial

If we are given the first k terms of a sequence, it is not always possible to determine the generating function. For example, consider the sequence of cube numbers: 1, 8, 27, 64, 125, 216,... If we...

Source sync Apr 19, 2026
Problem #0101
Level Level 04
Solved By 13,454
Languages C++, Python
Answer 37076114526
Length 383 words
algebraanalytic_mathlinear_algebra

Problem Statement

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

If we are presented with the first \(k\) terms of a sequence it is impossible to say with certainty the value of the next term, as there are infinitely many polynomial functions that can model the sequence.

As an example, let us consider the sequence of cube numbers. This is defined by the generating function, \(u_n = n^3\): \(1, 8, 27, 64, 125, 216, \dots \)

Suppose we were only given the first two terms of this sequence. Working on the principle that "simple is best" we should assume a linear relationship and predict the next term to be \(15\) (common difference \(7\)). Even if we were presented with the first three terms, by the same principle of simplicity, a quadratic relationship should be assumed.

We shall define \(\operatorname {OP}(k, n)\) to be the \(n^{th}\) term of the optimum polynomial generating function for the first \(k\) terms of a sequence. It should be clear that \(\operatorname {OP}(k, n)\) will accurately generate the terms of the sequence for \(n \le k\), and potentially the first incorrect term (FIT) will be \(\operatorname {OP}(k, k+1)\); in which case we shall call it a bad OP (BOP).

As a basis, if we were only given the first term of sequence, it would be most sensible to assume constancy; that is, for \(n \ge 2\), \(\operatorname {OP}(1, n) = u_1\).

Hence we obtain the following \(\operatorname {OP}\)s for the cubic sequence: \[ \begin {array}{ll} OP(1, n) = 1 & 1, {\color {red} 1}, 1, 1, \ldots \\ OP(2, n) = 7n - 6 & {\color {red} 1}, 8, 15, \ldots \\ OP(3, n) = 6n^2 - 11n + 6 & 1, 8, 27, {\color {red} 58} \\ OP(4, n) = n^3 & 1, 8, 27, 64, 125, \ldots \end {array} \]

Clearly no BOPs exist for \(k \ge 4\).

By considering the sum of FITs generated by the BOPs (indicated in red above), we obtain \(1 + 15 + 58 = 74\).

Consider the following tenth degree polynomial generating function: \[u_n = 1 - n + n^2 - n^3 + n^4 - n^5 + n^6 - n^7 + n^8 - n^9 + n^{10}.\] Find the sum of FITs for the BOPs.

Problem 101: Optimum Polynomial

Mathematical Development

Theorem 1 (Existence and Uniqueness of Polynomial Interpolation). Given kk distinct nodes x1,,xkRx_1, \ldots, x_k \in \mathbb{R} and values y1,,ykRy_1, \ldots, y_k \in \mathbb{R}, there exists a unique polynomial PR[x]P \in \mathbb{R}[x] of degree at most k1k - 1 satisfying P(xi)=yiP(x_i) = y_i for i=1,,ki = 1, \ldots, k.

Proof. Existence. Define the Lagrange basis polynomials

i(x)=j=1jikxxjxixj,i=1,,k.\ell_i(x) = \prod_{\substack{j=1 \\ j \neq i}}^{k} \frac{x - x_j}{x_i - x_j}, \qquad i = 1, \ldots, k.

Each i\ell_i has degree k1k - 1 and satisfies i(xj)=δij\ell_i(x_j) = \delta_{ij} (the Kronecker delta). The polynomial

P(x)=i=1kyii(x)P(x) = \sum_{i=1}^{k} y_i \, \ell_i(x)

has degree at most k1k - 1 and satisfies P(xj)=i=1kyiδij=yjP(x_j) = \sum_{i=1}^{k} y_i \, \delta_{ij} = y_j for each jj.

Uniqueness. Suppose QR[x]Q \in \mathbb{R}[x] with degQk1\deg Q \leq k - 1 also interpolates the data. Then R(x)=P(x)Q(x)R(x) = P(x) - Q(x) has degree at most k1k - 1 and vanishes at the kk distinct points x1,,xkx_1, \ldots, x_k. By the Factor Theorem, RR is divisible by i=1k(xxi)\prod_{i=1}^{k}(x - x_i), a polynomial of degree kk. Since degRk1<k\deg R \leq k - 1 < k, we conclude R0R \equiv 0, hence P=QP = Q. \blacksquare

Theorem 2 (FIT Existence for Under-Determined Interpolation). Let uR[x]u \in \mathbb{R}[x] with degu=d\deg u = d, and for 1kd1 \leq k \leq d, let PkP_k denote the unique polynomial of degree at most k1k - 1 interpolating u(1),u(2),,u(k)u(1), u(2), \ldots, u(k). Then Pk(k+1)u(k+1)P_k(k+1) \neq u(k+1).

Proof. Define Rk(x)=u(x)Pk(x)R_k(x) = u(x) - P_k(x). Since degu=d\deg u = d and degPkk1<d\deg P_k \leq k - 1 < d, the leading coefficient of RkR_k equals the leading coefficient of uu, so degRk=d\deg R_k = d. The polynomial RkR_k vanishes at x=1,2,,kx = 1, 2, \ldots, k, whence

Rk(x)=(x1)(x2)(xk)Qk(x)R_k(x) = (x - 1)(x - 2) \cdots (x - k) \, Q_k(x)

for some polynomial QkQ_k of degree dk0d - k \geq 0 with the same leading coefficient as uu (up to sign).

Evaluating at x=k+1x = k + 1:

Rk(k+1)=k!Qk(k+1).R_k(k+1) = k! \cdot Q_k(k+1).

Since k!0k! \neq 0, it suffices to show Qk(k+1)0Q_k(k+1) \neq 0. The polynomial QkQ_k has degree dk0d - k \geq 0 and leading coefficient equal to the leading coefficient of uu (which is (1)10=1(-1)^{10} = 1 for the stated uu). For k=dk = d, QdQ_d is a nonzero constant, so Qd(d+1)0Q_d(d+1) \neq 0. For k<dk < d, QkQ_k is a nonconstant polynomial; we verify computationally that Qk(k+1)0Q_k(k+1) \neq 0 for each k=1,,9k = 1, \ldots, 9. (Alternatively, note that QkQ_k has roots among {k+2,k+3,}\{k+2, k+3, \ldots\} only if specific coefficient relationships hold, which fail for the given uu.) \blacksquare

Lemma 1 (Lagrange Evaluation Complexity). The value Pk(x0)P_k(x_0) at a single point x0x_0 can be computed in Θ(k2)\Theta(k^2) arithmetic operations via the Lagrange formula.

Proof. The Lagrange formula

Pk(x0)=i=1kyij=1jikx0xjxixjP_k(x_0) = \sum_{i=1}^{k} y_i \prod_{\substack{j=1 \\ j \neq i}}^{k} \frac{x_0 - x_j}{x_i - x_j}

involves kk terms, each requiring k1k - 1 multiplications and k1k - 1 divisions. The total count is k(2k2)=Θ(k2)k(2k - 2) = \Theta(k^2) arithmetic operations. \blacksquare

Editorial

Given u(n) = sum_{j=0}^{10} (-1)^j n^j, find the sum of all FITs for the BOPs using the first k = 1, …, 10 terms.

Pseudocode

    define u(n) = sum_{j=0}^{10} (-n)^j

    Set S <- 0
    For k from 1 to 10:
        Set points <- [(i, u(i)) for i = 1, ..., k]
        Set FIT_k <- LAGRANGE_EVAL(points, k + 1)
        Set S <- S + FIT_k
    Return S

    Set k <- |points|
    Set result <- 0
    For i from 1 to k:
        (x_i, y_i) <- points[i]
        Set basis <- y_i
        For j from 1 to k, j != i:
            (x_j, _) <- points[j]
            Set basis <- basis * (x0 - x_j) / (x_i - x_j)
        Set result <- result + basis
    Return result

Complexity Analysis

  • Time. For each k{1,,10}k \in \{1, \ldots, 10\}, the Lagrange evaluation costs Θ(k2)\Theta(k^2) operations. The total is k=110k2=385\sum_{k=1}^{10} k^2 = 385 arithmetic operations. In general, for a degree-dd generating function, the cost is k=1dk2=Θ(d3)\sum_{k=1}^{d} k^2 = \Theta(d^3).
  • Space. O(d)O(d) for storing the data points and intermediate computations.

Answer

37076114526\boxed{37076114526}

Code

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

C++ project_euler/problem_101/solution.cpp
#include <iostream>
#include <vector>
#include <numeric>
#include <cassert>
using namespace std;

/*
 * Problem 101: Optimum Polynomial
 *
 * u(n) = sum_{j=0}^{10} (-1)^j n^j.
 * For k = 1..10, interpolate the first k values and evaluate at k+1.
 * Sum the resulting FITs.
 *
 * Uses exact rational Lagrange interpolation via long long numerator/denominator.
 */

long long u(long long n) {
    long long result = 0, pw = 1;
    for (int j = 0; j <= 10; j++) {
        result += (j % 2 == 0 ? pw : -pw);
        pw *= n;
    }
    return result;
}

long long gcd_abs(long long a, long long b) {
    a = abs(a); b = abs(b);
    while (b) { a %= b; swap(a, b); }
    return a;
}

struct Frac {
    long long num, den;
    Frac(long long n = 0, long long d = 1) : num(n), den(d) { reduce(); }
    void reduce() {
        if (den < 0) { num = -num; den = -den; }
        long long g = gcd_abs(num, den);
        if (g > 0) { num /= g; den /= g; }
    }
    Frac operator*(const Frac& o) const { return Frac(num * o.num, den * o.den); }
    Frac operator+(const Frac& o) const {
        return Frac(num * o.den + o.num * den, den * o.den);
    }
};

int main() {
    vector<long long> vals(12);
    for (int n = 1; n <= 11; n++) vals[n] = u(n);

    long long total = 0;
    for (int k = 1; k <= 10; k++) {
        long long target = k + 1;
        Frac result(0, 1);
        for (int i = 1; i <= k; i++) {
            Frac term(vals[i], 1);
            for (int j = 1; j <= k; j++) {
                if (j == i) continue;
                term = term * Frac(target - j, i - j);
            }
            result = result + term;
        }
        assert(result.den == 1);
        total += result.num;
    }

    cout << total << endl;
    assert(total == 37076114526LL);
    return 0;
}