拉格朗日插值

前言 : 本人数学水平较菜, 若有出错, 稍加原谅。

简介 :

一种由 n+1 个点 (xi,yi) 去求出最多为 n 次的多项式 : y=f(x) 使得其经过每一个点, 或者求出另一个在此函数的点 (x,y)

特定的, 我们钦定下文的 i,j[0,n]

拉格朗日基本多项式

li(x)=jinxxixixj

因为其构造巧妙, 我们可以发现 li(xi)=1, li(xj)=0 这一奇妙性质。

那么继续构造 f(x) 可以得到 :

f(x)=i=0nyili(x)

所以我们可以在 O(n) 的时间内计算单个 li(x) , 从而实现 O(n2) 插值出新的点 (x,y)

重心拉格朗日插值

这是一种增量式的拉格朗日插值计算方法。

考虑展开 f(x) :

f(x)=i=0nyij=0,jinxxixixj

我们令 g=i=0nxxi ,原式为 :

f(x)=gi=0nijnyi(xxi)(xixj)

我们只需要计算 ti=ijnyi(xxi)(xixj) 就可以得到 :

f(x)=gi=0ntixxi

我们发现 ti 是可以 O(n) 计算的, 十分优秀。

Bonus: 取值连续

很多时候, xi[1,n] 这段区间, 我们发现拉格朗日插值可以继续优化。

f(x)=i=0nyijinxxixixj

这个式子, 我们记录 :

prei=j=0nxxj

sufi=j=inxxj

对此, 我们发现非常巧妙的, 分母是阶乘的形式 :

f(x)=i=0nyiprei1sufi+1faci1facni

注意, 若 ni 位奇数, 那么分母是负的。

自此拉格朗日插值可以优化到 O(nlogn+nt) 其中 求逆元 + 单点求值。

板子 :

namespace lagrange {
	
	// nNode -> n - 1 -> f(x)
	const int MOD = 1e9 + 7, N = 5e3 + 5;
	
	int n, k, x[N], y[N], pre[N], suf[N], fac[N];
	
	inline void mul (int & x, int y) { x = x * y % MOD; }
	inline void add (int & x, int y) { x = (x + y) % MOD; }
	inline int qpow (int x, int y) {
		int s = 1;
		for ( ; y; mul(x, x), y >>= 1)
			if (y & 1) mul(s, x);
		return s;
	}
	
	inline int getG (int i, int pos) {
		int ans = y[i], s1 = 1, s2 = 1;
		for (int j = 1; j <= n; j ++) 
			if (j != i) mul(s1, pos - x[j]), mul(s2, x[i] - x[j]);
		ans = ans * (s1 * qpow(s2, MOD - 2) % MOD) % MOD;
		return ans;
	}
	inline void extendGet () {
		int ans = 0;
		cin >> n >> k;
		for (int i = 1; i <= n; i ++) cin >> x[i] >> y[i];
		for (int i = 1; i <= n; i ++) add(ans, getG(i, k));
		ans = (ans + MOD) % MOD, cout << ans;
	}
	inline int simpleGet (int n, int k) {
		// k + 1
		int ans = 0, y = 0;
		pre[0] = suf[k + 3] = fac[0] = 1;
		for (int i = 1; i <= k + 2; i ++) pre[i] = pre[i - 1] * (n - i) % MOD;
		for (int i = k + 2; i >= 1; i --) suf[i] = suf[i + 1] * (n - i) % MOD;
		for (int i = 1; i <= k + 2; i ++) fac[i] = fac[i - 1] * i % MOD;
		for (int i = 1; i <= k + 2; i ++) {
			add(y, qpow(i, k)); // get pos-val
			int a = pre[i - 1] * suf[i + 1] % MOD, b = fac[i - 1] * ((k - i) & 1 ? -1 : 1) * fac[k + 2 - i] % MOD;
			add(ans, y * a % MOD * qpow(b, MOD - 2) % MOD);
		}
		ans = (ans + MOD) % MOD;
		return ans;
	}
}

习题 :

P4781 模板

CF622F

inik 是个 k+1 次多项式, 那我们拿 [1,k+2] 去插值就可以了。

P4593

iim+1 大力拉插。

P3270

Orz 牛逼组合题。

我们记 fi,j 为前 i 门碾压 j 个人, 考虑到 j 单调不升, 有如下转移 :

fi,j=t=jkfi1,t(ttj)(nk1ri1(kj))g(i)

其中 g(i) 为这一门课的方案数, 枚举划分即可。

g(i)=j=1uijnri(uij)ri1

其中 g(i) 可以直接插值。

O(n2mlog2umax)

解决这一问题。

  • 差分理论 :

f(x)n 次的, 那么 f(x)f(x1)n1 次的。

P4463 :

fi,jfi,j1=jfi1,j1

猜测为关于 j 的多项式 :

g(i)1=g(i1)+1

g(i)=g(i1)+2

那么就可以插值了。

CF995F ;

fu,d=fu,d1+fv,d

fu,dfu,d1=fv,d

考虑这是关于 d 的函数 :

gu1=gv

我不会归纳之类的, 但是考虑到叶子结点 gv=1

所以对于其父亲 u 有 : gu=sizeu

那么这样一层一层地推上去,都有 : grt=sizert

所以, f1,d 是一个关于 dsize1 次多项式。

大力插值即可。

posted @   Cust10  阅读(163)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示