The operations and their costs

OperationNaiveFastMethod
Add / subtractcoefficientwise
Scalar multiply
MultiplyFFT/NTT
Divide by synthetic division
Divide with remainderNewton on the reversed polynomial
Evaluate at one pointHorner
Evaluate at pointsmultipoint evaluation
Interpolate from pointsinverse multipoint
Derivative / integralcoefficientwise
GCDhalf-GCD
Composition Brent-Kung
Power
Shift a convolution with binomials

Horner’s method

long long evaluate(const vector<long long>& a, long long x, long long MOD) {
    long long res = 0;
    for (int i = a.size() - 1; i >= 0; i--) res = (res * x + a[i]) % MOD;
    return res;
}

multiplications and additions — optimal for a single evaluation, and the standard way to compute a polynomial hash.

Division with remainder

with . Naive long division is ; the fast version uses the reversal trick:

so computed as a power series inverse. Then .

// rev(P)[i] = P[deg - i]
pair<Poly,Poly> divmod(Poly a, Poly b) {
    int d = a.size() - b.size();
    if (d < 0) return {{0}, a};
    Poly ra = reversed(a), rb = reversed(b);
    Poly q = reversed(mulTrunc(ra, inverse(rb, d + 1), d + 1));
    Poly r = sub(a, mul(q, b));
    r.resize(b.size() - 1);
    return {q, r};
}

Synthetic division by

// divide by (x - a); returns the quotient, and the remainder is P(a)
vector<long long> synthetic(vector<long long> p, long long a, long long MOD) {
    for (int i = p.size() - 2; i >= 0; i--)
        p[i] = (p[i] + a * p[i+1]) % MOD;
    long long rem = p[0];
    p.erase(p.begin());
    return p;                                    // remainder = rem = P(a)
}

, and it is the same recurrence as Horner — evaluation and division by a linear factor are the same computation.

Roots and factorisation

TaskMethod
Rational roots over rational root theorem: ,
Roots modulo a prime, then Cantor-Zassenhaus
Real rootsSturm sequences + bisection
All complex rootsDurand-Kerner, or companion-matrix eigenvalues
Squarefree part
Full factorisation over SFF → DDF → EDF
Factorisation over factor mod , Hensel lift, recombine

Useful identities

The last one (Vieta’s formulas) converts between roots and coefficients, and the product is computable in by divide and conquer — the same recursion used for multipoint evaluation.

// product of (x - r_i) in O(n log^2 n)
Poly buildProduct(int lo, int hi) {
    if (hi - lo == 1) return {MOD - r[lo], 1};
    int mid = (lo + hi) / 2;
    return mul(buildProduct(lo, mid), buildProduct(mid, hi));
}

Representation

For contest use, a vector<long long> with index = degree (little-endian) is the right choice: addition is a loop, multiplication feeds straight into NTT, and the derivative is a shift.

Trim trailing zeros after every operation, or the degree bookkeeping drifts.

See also: FFT and NTT · Formal Power Series · Lagrange Interpolation