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 May 21, 2026
Problem #0101
Level Level 04
Solved By 13,454
Languages C++, Python
Answer 37076114526
Length 448 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,…,xk∈Rx_1, \ldots, x_k \in \mathbb{R} and values y1,…,yk∈Ry_1, \ldots, y_k \in \mathbb{R}, there exists a unique polynomial P∈R[x]P \in \mathbb{R}[x] of degree at most k−1k - 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=1j≠ikx−xjxi−xj,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 k−1k - 1 and satisfies ℓi(xj)=δij\ell_i(x_j) = \delta_{ij} (the Kronecker delta). The polynomial

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

has degree at most k−1k - 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 Q∈R[x]Q \in \mathbb{R}[x] with deg⁡Q≤k−1\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 k−1k - 1 and vanishes at the kk distinct points x1,…,xkx_1, \ldots, x_k. By the Factor Theorem, RR is divisible by ∏i=1k(x−xi)\prod_{i=1}^{k}(x - x_i), a polynomial of degree kk. Since deg⁡R≤k−1<k\deg R \leq k - 1 < k, we conclude R≡0R \equiv 0, hence P=QP = Q. ■\blacksquare

Theorem 2 (FIT Existence for Under-Determined Interpolation). Let u∈R[x]u \in \mathbb{R}[x] with deg⁡u=d\deg u = d, and for 1≤k≤d1 \leq k \leq d, let PkP_k denote the unique polynomial of degree at most k−1k - 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 deg⁡u=d\deg u = d and deg⁡Pk≤k−1<d\deg P_k \leq k - 1 < d, the leading coefficient of RkR_k equals the leading coefficient of uu, so deg⁡Rk=d\deg R_k = d. The polynomial RkR_k vanishes at x=1,2,…,kx = 1, 2, \ldots, k, whence

Rk(x)=(x−1)(x−2)⋯(x−k) Qk(x)R_k(x) = (x - 1)(x - 2) \cdots (x - k) \, Q_k(x)

for some polynomial QkQ_k of degree d−k≥0d - 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 d−k≥0d - 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=1kyi∏j=1j≠ikx0−xjxi−xjP_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 k−1k - 1 multiplications and k−1k - 1 divisions. The total count is k(2k−2)=Θ(k2)k(2k - 2) = \Theta(k^2) arithmetic operations. ■\blacksquare

Editorial

For each kk, we need the polynomial of degree at most k−1k-1 that agrees with the true sequence at n=1,2,…,kn = 1, 2, \ldots, k, and then we need its first failure at n=k+1n = k+1. Because only that one value is required, it is cleaner to evaluate the interpolating polynomial directly in Lagrange form than to solve for its coefficients explicitly.

The implementation therefore builds the first kk sample points, evaluates the unique interpolant at k+1k+1 using exact rational arithmetic, and adds that FIT to a running total. Repeating this for k=1k = 1 through 1010 produces exactly the sum requested in the problem.

Pseudocode

Start with a running total of zero.

For each k from 1 through 10:
    Form the sample points (1, u(1)), (2, u(2)), ..., (k, u(k)).
    Evaluate the degree-(k-1) interpolating polynomial at n = k + 1 by summing its Lagrange basis terms exactly.
    Add that value to the running total.

Return the running total.

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;
}