본문으로 건너뛰기
김신건의 로그

Multipoint Evaluation

· 수정 · 📖 약 2분 · 854자/단어 #algorithm #math #polynomial #multipoint-evaluation
Multipoint Evaluation, 다중점 평가

정의

Multipoint Evaluation 은 차수 M 의 다항식 P(x)N 개의 점 x_1, ..., x_N 에서 동시에 평가 (P(x_i) 를 모두 구함) 하는 것을 O((N + M) log²(N+M)) 에 계산하는 알고리즘.

naive 는 점당 O(M) → 총 O(NM). FFT/NTT + 다항식 나눗셈으로 한 단계 빠르게. Polynomial Interpolation역방향.

문제 상황과 동기

차수 M 의 다항식 P(x) = a_0 + a_1 x + ... + a_M x^MN 개 점 x_1, ..., x_N 에서 평가하려면, 각 점마다 Horner 법으로 O(M) → 총 O(NM).

N = M = 10^5 이면 O(NM) = 10^10, 불가능. 대표 응용: 다항식 보간 (N+1 점으로 유일 다항식 복원) 의 검증, 생성 함수 계산, 분할정복 다항식 곱의 체크.

핵심 아이디어: 평가점들을 이진 트리로 나누고, 각 노드는 자식들의 평가점을 모두 zero 로 만드는 다항식 Π (x - x_i) 를 저장. P(x) 를 트리 루트부터 내려가며 mod 연산 (다항식 나머지) 로 차수를 절반씩 줄이면, 리프에서 상수 한 개만 남는다. 각 단계 다항식 나눗셈 O(K log K), 총 O((N+M) log²(N+M)).

이는 다항식 다중점 평가의 사실상 유일한 subquadratic 솔루션. Polynomial Interpolation 과 쌍을 이루는 dual operation.

시각화

핵심 아이디어

평가점들로부터 segment tree of polynomials 를 만든다. 각 노드는 자식들이 담는 평가점들의 곱 다항식 Π (x - x_i).

1단계: 트리 구축

build_tree(l, r):
    if r - l == 1: return (x - x_l)
    mid = (l+r)/2
    left = build_tree(l, mid)
    right = build_tree(mid, r)
    return left * right    # FFT/NTT 다항식 곱, O(K log K)

총 O((N+M) log(N+M)).

2단계: 평가 (top-down)

eval(P, node, l, r):
    P = P mod node.poly        # 다항식 나눗셈, O(K log K)
    if r - l == 1:
        return P 의 상수항     # = P(x_l)
    eval(P, left_child, l, mid)
    eval(P, right_child, mid, r)

각 레벨 O((N+M) log(N+M)), 총 log N 레벨 → O((N+M) log²(N+M)).

Step trace (작은 예)

P(x) = x^2 + 2x + 3, 평가점 [1, 2, 3, 4]

트리:
        (x-1)(x-2)(x-3)(x-4)
       /                    \
  (x-1)(x-2)            (x-3)(x-4)
   /     \               /     \
 (x-1)  (x-2)         (x-3)  (x-4)

eval(P, root):
  P mod (x-1)(x-2)(x-3)(x-4) = P (차수 2 < 4이므로 변화 없음)
  
  eval(P, left): P mod (x-1)(x-2) = P mod (x^2 - 3x + 2)
    → 나머지 r = ... (차수 1 이하)
    eval(r, x-1): r(1) = 1 + 2 + 3 = 6
    eval(r, x-2): r(2) = 4 + 4 + 3 = 11
  
  eval(P, right): P mod (x-3)(x-4) = ...
    → P(3) = 18, P(4) = 27

결과: [6, 11, 18, 27]

구현

O((N+M) log²) 다중점 평가 (스켈레톤 + 의사코드)

구현이 매우 길고 (다항식 곱, 나눗셈, 역원 계산 포함 ~600줄), 버그가 나기 쉬우므로 검증된 라이브러리 (AtCoder Library, ho94949 구현) 사용 권장. 아래는 핵심 구조만.

// O((N+M) log^2) Multipoint Evaluation
// 다항식 곱, 나눗셈, 역원 계산 등 기본 다항식 라이브러리 필요 (생략)
// 실제 구현은 https://judge.yosupo.jp/submission/236749 등 참고
#include <vector>
using namespace std;
using poly = vector<long long>;   // 계수 표현

// 다항식 곱셈 (NTT), O(n log n)
poly multiply(poly a, poly b);

// 다항식 나눗셈 P mod Q, O(n log n) (역원 + NTT)
poly mod(poly P, poly Q);

// 트리 노드: [l, r) 구간의 평가점을 zero로 만드는 다항식
struct TreeNode {
    int l, r;
    poly prod;   // Π_{i in [l,r)} (x - x_i)
    TreeNode *left, *right;
};

// 1단계: 평가점 트리 구축
TreeNode* build_tree(const vector<long long>& xs, int l, int r) {
    auto node = new TreeNode{l, r, {}, nullptr, nullptr};
    if (r - l == 1) {
        // 리프: (x - xs[l])
        node->prod = {-xs[l], 1};   // 계수 표현: a0 + a1*x
        return node;
    }
    int mid = (l + r) / 2;
    node->left = build_tree(xs, l, mid);
    node->right = build_tree(xs, mid, r);
    node->prod = multiply(node->left->prod, node->right->prod);
    return node;
}

// 2단계: P(x) 를 각 점에서 평가
void eval_tree(poly P, TreeNode* node, vector<long long>& result) {
    P = mod(P, node->prod);   // P %= node.prod
    if (node->r - node->l == 1) {
        // 리프: P는 상수 (또는 0), P(xs[l]) = P의 상수항
        result[node->l] = P.empty() ? 0 : P[0];
        return;
    }
    eval_tree(P, node->left, result);
    eval_tree(P, node->right, result);
}

// 전체 평가
vector<long long> multipoint_eval(poly P, const vector<long long>& xs) {
    int n = xs.size();
    auto tree = build_tree(xs, 0, n);
    vector<long long> result(n);
    eval_tree(P, tree, result);
    return result;   // result[i] = P(xs[i])
}

다항식 곱 / 나눗셈 / 역원은 NTT 기반. 각 연산 O(K log K).

복잡도

작업비용
트리 구축O((N+M) log(N+M))
평가O((N+M) log²(N+M))
전체O((N+M) log²(N+M))

N = M = 10^5 → ~10^7 연산. NTT 상수항이 크므로 실제로는 N ≤ 10^4 정도에서 실용.

응용

1. 다항식 보간의 역

N+1 점에서의 평가 → naive O(N²) 보다 빠르게 평가.

2. 분할정복 다항식 곱

(x - r_1)(x - r_2)...(x - r_N) 계산도 같은 트리.

3. Game with Polynomials 류

여러 다항식의 동시 평가가 필요한 게임 / 카운팅 문제.

함정

1. mod 환경

NTT 친화 mod (998244353) 가 표준. 다른 mod 는 3-NTT + CRT.

2. 다항식 reciprocal

빠른 나눗셈에는 f(x) 의 역원을 사전계산 (Newton iteration). 한 노드당 한 번.

3. 구현 길이

다항식 곱 + 다항식 나눗셈 + 트리 분할정복. 600 ~ 1000 줄. 검증된 ho94949 / atcoder library 권장.

4. 평가점 중복

평가점이 중복이면 트리 빌드에서 0 차수 처리 주의.

BOJ 연습 문제

번호제목링크
BOJ 18168Game with Polynomials 2kokoa-lab

다른 출처 연습 문제

출처제목링크
Library CheckerMultipoint Evaluationhttps://judge.yosupo.jp/problem/multipoint_evaluation

참고

이 글의 용어 (4개)
FFT, NTTalgorithm
정의 FFT (Fast Fourier Transform, 고속 푸리에 변환) 은 길이 인 수열의 이산 푸리에 변환 (DFT) 을 O(n log n) 에 계산하는 분할정복 알고리즘…
Generating Functionalgorithm
정의 Generating Function (생성 함수) 은 수열 를 형식 멱급수 (formal power series) 으로 인코딩한 것. 수열의 산수 를 다항식 / 멱급수의 대…
Polynomial Division, Kitamasaalgorithm
정의 Kitamasa 는 길이 의 선형 점화식 의 번째 항을 O(K² log n) 또는 FFT/NTT 와 결합해 O(K log K · log n) 에 계산하는 알고리즘. 행렬 거…
Polynomial Interpolationalgorithm
정의 Polynomial Interpolation (다항식 보간) 은 N+1 개의 점 으로부터 유일하게 결정되는 차수 ≤ N 의 다항식 를 복원하는 것. PS 에서는 DP 의 결…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기