Lagrange插值复习笔记
我们知道一个 \(n\) 次多项式可以由 \(n + 1\) 个点确定,那么拉格朗日插值可以做到在已知的点能确定函数的情况下,不求出这个多项式本身,而能以 \(O(n^2)\) 的复杂度确定 \(f(k)\) 的值。
拉格朗日插值多项式公式如下:
\[f(k) = \sum_{i=0}^{n} y_{i} \prod_{\substack{j=0 \\ j \neq i}}^{n} \frac{k - x[j]}{x[i] - x[j]}
\]
板子代码(对标 luogu P4781):
const int mod = 998244353;
inline void inc(int &x, int y) { x = x + y >= mod ? x + y - mod : x + y; }
inline void dec(int &x, int y) { x = x - y >= 0 ? x - y : x - y + mod; }
inline int qpow(int a, int b) {
int ret = 1;
for (; b; b >>= 1, a = 1ll * a * a % mod)
if (b & 1) ret = 1ll * ret * a % mod;
return ret;
}
inline int Lagrange(vector <pii> p, int n, int k) {
int ret = 0;
for (int i = 1, s1, s2; i <= n; i++) {
s1 = p[i - 1].second, s2 = 1;
for (int j = 1; j <= n; j++) if (i != j)
s1 = 1ll * s1 * (k - p[j - 1].first) % mod,
s2 = 1ll * s2 * (p[i - 1].first - p[j - 1].first) % mod;
dec(s1, 0), dec(s2, 0);
inc(ret, 1ll * s1 * qpow(s2, mod - 2) % mod);
}
return ret;
}
典型例题 I. DAG Query(The 2025 ICPC Asia EC Regionals Online Contest (II))
可以看出 \(c\) 对路径的影响是指数级别的,每一条边都要乘一次。在图和边权固定的情况下,\(f(1,n,c)\) 是一个关于 \(c\) 的 \(n - 1\) 次多项式,且没常数项。所以我们可以先变形为 \(xF(x)\) ,其中 \(F(x)\) 是一个 \(n - 2\) 次的多项式,我们可以用 \(n - 1\) 个点确立,这正好只要问999次符合题目条件。
int n, m; vector <pii> p; vector <int> G[1005];
inline int read(int s, int t, int c) {
cout << "? " << s << ' ' << t << ' ' << c << endl;
cout.flush();
int f; cin >> f; return f;
}
inline void write(void) {
cout << "!" << endl; cout.flush();
int c; cin >> c;
cout << 1ll * Lagrange(p, n - 1, c) * c % mod << endl; cout.flush();
}
signed main(void) {
cin >> n >> m;
for (int i = 1, u, v; i <= m; i++) {
read(u), read(v);
G[u].push_back(v);
}
for (int i = 1; i <= n - 1; i++) {
int x = i, y = 1ll * read(1, n, i) * qpow(x, mod - 2) % mod;
p.push_back(Mp(x, y));
}
write();
//fwrite(pf, 1, o1 - pf, stdout);
return 0;
}
典型例题 C. Fenwick Tree(Codeforces Round 942 (Div. 1)
这题显然有组合数学算贡献的方法,但是树状数组是 \(log_2(n)\) 层的,也就说结果是个 \(log_2(n)\) 阶的多项式。所以我们也可以暴力求前面 \(20\) 层的值然后 \(Lagrange插值\) 做这道题。
const int mod = 998244353;
inline int qpow(int a, int b) {
int ret = 1;
for (; b; b >>= 1, a = 1ll * a * a % mod)
if (b & 1) ret = 1ll * ret * a % mod;
return ret;
}
inline void inc(int &x, int y) { x = x + y >= mod ? x + y - mod : x + y; }
inline void dec(int &x, int y) { x = x - y >= 0 ? x - y : x - y + mod; }
const int N = 2e5 + 5;
int T, n, k, a[N][21], x[21], y[21];
inline int L(void) {
int ans = 0;
for (int i = 1, s1, s2; i <= 20; i++) {
s1 = y[i], s2 = 1;
for (int j = 1; j <= 20; j++) if (i != j)
s1 = 1ll * s1 * (k - x[j]) % mod,
s2 = 1ll * s2 * (x[i] - x[j]) % mod;
inc(ans, 1ll * s1 * qpow(s2, mod - 2) % mod); dec(ans, 0);
} return ans;
}
signed main(void) {
for (read(T); T; T--) {
read(n), read(k);
for (int i = 1; i <= n; i++) read(a[i][1]);
for (int i = 2; i <= 20; i++) {
for (int j = 1; j <= n; j++) a[j][i] = a[j][i - 1];
for (int j = 1; j <= n; j++) {
for (int k = j - lowbit(j) + 1; k < j; k++)
a[j][i] = (a[j][i] - a[k][i] + mod) % mod;
}
}
for (int i = 1; i <= n; i++) {
vector<signed> Q;
for (int j = 1; j <= 20; j++) x[j] = j - 1, y[j] = a[i][j];
writeln(L(), " \n"[i == n]);
}
}
//fwrite(pf, 1, o1 - pf, stdout);
return 0;
}

浙公网安备 33010602011771号