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;
}
posted @ 2025-09-19 21:35  EternalEpic  阅读(23)  评论(0)    收藏  举报