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