Evaluate a degree- polynomial at arbitrary points in , instead of by repeated Horner.
The idea: a product tree
Build a divide-and-conquer tree over the evaluation points, where each node stores the product over its range.
(x-x0)(x-x1)(x-x2)(x-x3)
/ \
(x-x0)(x-x1) (x-x2)(x-x3)
/ \ / \
(x-x0) (x-x1) (x-x2) (x-x3)
Building it is — levels, each doing of NTT multiplication.
Evaluation — descend with remainders
By the remainder theorem, . So descend the tree, replacing by at each step. The remainder’s degree shrinks with the node’s range, so the total work per level is .
void evalRec(const Poly& P, int node, int lo, int hi, vector<long long>& out) {
if (hi - lo == 1) { out[lo] = P.empty() ? 0 : P[0]; return; }
int mid = (lo + hi) / 2;
evalRec(P % tree[2*node], 2*node, lo, mid, out);
evalRec(P % tree[2*node+1], 2*node+1, mid, hi, out);
}overall — the extra comes from the polynomial division at each node.
Interpolation — the reverse
Given , recover the polynomial. By Lagrange,
- Build the product tree and .
- Compute and evaluate it at all by multipoint evaluation — this gives all the denominators at once.
- Combine bottom-up: at each node, .
.
The cost table
| Task | Naive | Fast |
|---|---|---|
| Evaluate at 1 point | — | |
| Evaluate at consecutive points | (a convolution) | |
| Evaluate at points in geometric progression | (chirp-z) | |
| Evaluate at arbitrary points | ||
| Interpolate from arbitrary points | ||
| Interpolate from consecutive points | (Lagrange) |
Check the point structure first
The special cases are dramatically cheaper. Consecutive points give interpolation and evaluation; geometric points give via the chirp-z transform. Only genuinely arbitrary points need the machinery — and in contests the points are usually
What it enables
| Application | Use |
|---|---|
| Convert between coefficient and value representations | both directions |
| Fast polynomial GCD (half-GCD) | uses the same product-tree recursion |
| Polynomial factorisation | evaluating at many points |
| Chinese remaindering of polynomials | the same tree |
| $n! \bmod p$ in $\tilde O(\sqrt p)$ | evaluate a product polynomial at points |
| Shift a polynomial’s argument | via evaluation and interpolation |
| Multi-modular CRT reconstruction | the integer analogue of the same tree |
in
Define with . Then
and the values are a multipoint evaluation at points in arithmetic progression. Total — the standard way to compute a factorial modulo a prime when is around .
The product tree pattern
Building a balanced tree of products, then descending with remainders, is a reusable structure. The same shape appears in:
- CRT reconstruction from many moduli in ;
- fast polynomial GCD (half-GCD);
- batch modular inverse (a linear special case);
- segment trees storing products.
When it is worth it
The constant factor is significant — several NTTs per node. For , the Horner loop is faster in practice. Multipoint evaluation earns its place at , which is rare but real.
See also: Lagrange Interpolation · FFT and NTT · Polynomial Arithmetic