「笔记」拉格朗日插值


简介

对于 k 次多项式函数 F(x)
若已知 k+1 个点值,则可构造出多项式。
有:

F(x)=i=1k+1yiijxxjxixj

正确性详见 拉格朗日插值


正确性

k+1 个点值代入即可检验。
x=xk 时,对 i 进行讨论:

  1. ik 时,存在一个 j 满足 j=k
    对于乘积项的分子 ijxxj,当 j=k 时,xxj=0
    对答案无贡献。
  2. i=k 时,乘积项变为 ijxixjxixj
    其值恒等于 1

模板题

P4781 【模板】拉格朗日插值

//
/*
By:Luckyblock
*/
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <algorithm>
#define ll long long
const int MARX = 2010;
const ll Mod = 998244353;
//=============================================================
ll ans, N, K, X[MARX], Y[MARX];
//=============================================================
inline int read()
{
int f = 1, w = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for(; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
ll qpow(ll x, ll y, ll mod)
{
ll ret = 1;
for(; y; x = x * x % mod, y >>= 1)
if(y & 1) ret = ret * x % mod;
return ret;
}
//=============================================================
int main()
{
N = read(), K = read();
for(int i = 1; i <= N; i ++) X[i] = read(), Y[i] = read();
for(int i = 1; i <= N; i ++)
{
ll tmp = 1ll;
for(int j = 1; j <= N; j ++)
if(i != j) tmp = tmp * (X[i] + Mod - X[j]) % Mod;
tmp = qpow(tmp, Mod - 2, Mod);
for(int j = 1; j <= N; j ++)
if(i != j) tmp = tmp * (K + Mod - X[j]) % Mod;
tmp = tmp * Y[i] % Mod, ans = (ans + tmp) % Mod;
}
printf("%lld", ans);
system("pause");
return 0;
}

自然幂数之和

CF622F The Sum of the k-th Powers

定义前 n 个自然数 k 次幂的和为:

Sk(n)=i=1nik

给定 n,k,求 Sk(n)
1n109, 1k106

性质

Sk(n) 为关于 nk+1 次多项式。

证明考虑对 k 进行归纳。
k=0 时,Sk(n)=n,结论成立。
k=d 时:

通过二项式定理化简,提出一项相消,有:

(i+1)d+1id+1=j=0d+1(d+1j)ijid+1=j=0d(d+1j)ij

(i+1)d+1id+1 求和,有:

i=1n{(i+1)d+1id+1}=i=1nj=0d(d+1j)ij

发现 (d+1j) 只与 j 有关,调换求和顺序,有:

i=1nj=0d(d+1j)ij=j=0d(d+1j)i=1nij=j=0d(d+1j)Sj(n)

化出了有趣的玩意。
展开左侧 id+1 的求和式相消,则有:

(n+1)d+11=j=0d(d+1j)Sj(n)

提出右侧 j=d 时的 Sd(n)

(d+1d)Sd(n)=(n+1)d+1j=0d1{(d+1j)Sj(n)}1

二项式定理展开右侧,并略做处理:

Sd(n)=1d+1{j=0d+1njj=0d1{(d+1j)Sj(n)}1}

对于右侧,通过数学归纳得到 Sj(n) 为关于 nj 次多项式。
则整个式子最高次项出现在 j=0d+1nj 中,次数为 d+1
得证。

具体实现

由性质,Sk(n) 为关于 nk+1 次多项式,需要 k+2 个点值进行构造。
可以直接取 k+1 个点,按照定义计算出 Sk(n),构造多项式。
复杂度 O(k2)?我觉得不行。

题目对选择的点并没有要求,考虑选取一段连续的点进行优化。
使 xi=i,则选择的点集为 {(i,Sk(i))iN+,ik+2}
按照定义递推出来即可,复杂度 O(klogk)

考虑要求的点 (n,Sk(n)),将其代入插值公式,有:

Sk(n)=i=1k+2Sk(i)ijnjij

发现乘积项的分母与 n 无关,提出来:

Sk(n)=i=1k+2Sk(i)ij(nj)ij(ij)

手玩一下乘积项的变化规律。

对于分母,jk+2,在已知 i 时有:

1ij(ij)=1i(i1)(i2)1×(1)(k+2i1)(k+2i)=(1)k+2i1i!(k+2i)!

可先预处理阶乘再求逆元,快速得到分母的值。

对于分子,也暴力拆一波:

ij(nj)=n(n1)(n(i1))(n(i+1))(n(k+2))=(j=1i1(nj))(j=i+1k+2(nj))

考虑维护 (nj) 的 前/后 缀积,可快速得到分子的值。

则有:

Sk(n)=i=1k+2(1)k+2iSk(i)(j=1i1(nj))(j=i+1k+2(nj))i!(k+2i)!

复杂度

O(klogk) 处理 k+2 个连续点值。
O(n) 预处理前/后 缀积,阶乘。
求逆元时可以 O(n) 预处理,也可以单次 O(logk)

总复杂度 O(klogk)

优缺点

优点:简单好写,复杂度优秀,就感觉到快。

缺点:出现了除法,需要求逆元,需保证模数为质数。

若模数不为质数怎么办? 可利用 斯特林数/伯努利数 求解。
伯努利数求解方法 详见 皎月半洒花的题解

斯特林数求解方法 复杂度 O(k2),无法通过本题,详见 自然数幂之和 - Luckyblock


写在最后

参考资料:
拉格朗日插值 - OI Wiki

posted @   Luckyblock  阅读(560)  评论(0编辑  收藏  举报
编辑推荐:
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
阅读排行:
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· 分享4款.NET开源、免费、实用的商城系统
· 解决跨域问题的这6种方案,真香!
· 一套基于 Material Design 规范实现的 Blazor 和 Razor 通用组件库
· 5. Nginx 负载均衡配置案例(附有详细截图说明++)
点击右上角即可分享
微信分享提示