A polynomial of degree is uniquely determined by its values at distinct points:

General points —

long long lagrange(const vector<long long>& x, const vector<long long>& y,
                   long long target, long long MOD) {
    int n = x.size();
    long long res = 0;
    for (int i = 0; i < n; i++) {
        long long num = 1, den = 1;
        for (int j = 0; j < n; j++) {
            if (j == i) continue;
            num = num * ((target - x[j]) % MOD + MOD) % MOD;
            den = den * ((x[i] - x[j]) % MOD + MOD) % MOD;
        }
        res = (res + y[i] % MOD * num % MOD * powmod(den, MOD - 2, MOD)) % MOD;
    }
    return res;
}

with a modpow per term; if you batch the inverses.

Consecutive points —

When the sample points are , the products telescope into factorials:

with and — both computable as prefix and suffix products.

long long lagrangeConsecutive(const vector<long long>& y, long long k, long long MOD) {
    int n = y.size();                                       // points x = 0..n-1
    if (k < n) return y[k];
    vector<long long> pre(n + 1, 1), suf(n + 1, 1);
    for (int i = 0; i < n; i++) pre[i+1] = pre[i] * ((k - i) % MOD) % MOD;
    for (int i = n - 1; i >= 0; i--) suf[i] = suf[i+1] * ((k - i) % MOD) % MOD;
 
    long long res = 0;
    for (int i = 0; i < n; i++) {
        long long num = pre[i] * suf[i+1] % MOD;
        long long den = invFact[i] * invFact[n-1-i] % MOD;
        long long term = y[i] * num % MOD * den % MOD;
        res = ((n - 1 - i) & 1) ? (res - term + MOD) % MOD : (res + term) % MOD;
    }
    return res;
}

after precomputing factorials — this is the version that appears in contests.

The killer application: sums of powers

is a polynomial in of degree . So compute by brute force in , then interpolate to get for up to in .

long long powerSum(long long n, int k, long long MOD) {
    vector<long long> y(k + 2, 0);
    for (int i = 1; i <= k + 1; i++)
        y[i] = (y[i-1] + powmod(i, k, MOD)) % MOD;
    return lagrangeConsecutive(y, n, MOD);                  // points 0..k+1
}

The same trick handles any quantity known to be polynomial in : prefix sums of a polynomial, counts satisfying a polynomial formula, and DP answers that are eventually polynomial.

Recognising “the answer is a polynomial”

This is the real skill. Signals:

  • the answer is a sum of a polynomial over a range → degree increases by 1;
  • the answer counts lattice points in a region scaling linearly with (Ehrhart polynomials);
  • a DP whose transition is linear with constant coefficients, evaluated at ;
  • the problem gives huge but the structure only depends on a small degree.

Verification: compute the first values by brute force, interpolate from the first , and check that the predicted values match the rest. If they do, the degree guess is right.

Fast interpolation and evaluation

TaskNaiveFast
Value at one point, general —
Value at one point, consecutive —
Coefficients from points
Values at new points (multipoint)
Shift

Newton’s divided differences

An alternative form that allows adding points incrementally:

with the computed by a divided-difference table. to build, but adding one new point is rather than a full rebuild — useful when the sample set grows.

Pitfalls

Three traps

  1. Repeated makes the denominator zero. Deduplicate first.
  2. Wrong degree. Interpolating points assumes degree ; if the true degree is higher, the answer is silently wrong. Always verify with extra points.
  3. The target coincides with a sample point. Return directly rather than dividing by zero.

See also: Multipoint Evaluation · Polynomial Arithmetic · Combinatorics