拉格朗日介绍
先说说拉格朗日是啥吧
首先 拉格朗日插值是给你 n+1
个点 $(x,y)$ 然后根据这n
个点可以$O(n^2)$的求出多项式的系数。也就是解出这个多项式的答案。
假设给你一个多项式
$y=a_0+a_1x+a_2x^2$
然后给你3
个解$(x1,y1)(x2,y2)(x3,y3)$你第一个想法是怎么解?解方程啊是不是
代进去是不是这样
然年后解这个方程?
解这个方程复杂度多少,高斯消元O(n^3)很显然复杂度高了。
拉格朗日就比较厉害了他能O(n^2)解决
首先 假设一个多项式$f_1(x)= b_0 + b_1x+b_2x^2$
当他$x=x_1$解是1
,$x_2$ $x_3$ 解是 0
同理再假设 $f_2(x)$ $f_3(x)$
然后$L(x)=y_1f_1(x)+y_2f_2(x)+y_3f_3(x)$,这个就是最开始那个方程,不信?你分别把$x_1,x_2,x_3$ 带进去解绝对是 $y_1,y_2,y_3$。
那么问题来了后面$f_1(x)$这个多项式怎么求出来????
这就是拉格朗日基本公式
再来一遍,这就是拉格朗日基本公式
把这个多项式展开会发现非常神奇的事,当$x=x_j$的时候刚好等于1
否则等于0
,刚好满足了原来所需要的方程式。就是下面这样:
最终表达式
怕你还是看不懂,举个例子给你看
$f(4)=10\ f(5)=5.25\ f(6)=1$ 求 $f(18)$
首先写出拉格朗日基本多项式
此时代入18
:$f(18)=p(18)=-11$
还有一个问题你们肯定很想问。。。知道公式之后怎么解。。。
对于这个问题
分母 是不是每次算一下就行了,答案是固定的
分子是不是一个大的多项式里面少了一个,就预处理出总的多项式然后,模拟除一下$(x+c)$的多项式
理论知识全部搞定,下面就给你贴模板了
板子
1 | //这个是杜教的板子 我打了点注释 |
然后下面这个是求多项式的1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58LL temp[maxn];
void mul(LL *f, int len, LL t) { //len为多项式的次数+1,函数让多项式f变成f*(x+t)
for (int i = len; i > 0; --i) {
temp[i] = f[i];
f[i] = f[i - 1];
}
temp[0] = f[0], f[0] = 0;
for (int i = 0; i <= len; ++i) {
f[i] = (f[i] + t * temp[i]) % mod;
}
}
void dev(LL *f, LL *r, LL t, int len) { //f是被除多项式的系数,r保存f除以x+t的结果 len是最高次项
for (int i = 0; i <= len; ++i) {
temp[i] = f[i];
}
for (int i = len; i > 0; --i) {
r[i - 1] = temp[i];
temp[i - 1] = (temp[i - 1] - t * temp[i]) % mod;
}
return;
}
LL a[maxn], b[maxn], c[maxn];
LL x[maxn], y[maxn]; //x,y输入从 1开始到n
int n;
void lglr() {
memset(a, 0, sizeof a);
b[1] = 1, b[0] = -x[1];
for (int i = 2; i <= n; ++i) {
mul(b, i, -x[i]);
}//预处理(x-x1)*(x-x2)...*(x-xn)
for (int i = 1; i <= n; ++i) {
LL fz = 1;
for (int j = 1; j <= n; ++j) {
if (j == i) continue;
fz = fz * (x[i] - x[j]) % mod;
}
fz = qm(fz, mod - 2);
fz = fz * y[i] % mod;//得到多项式系数
dev(b, c, -x[i], n);//得到多项式,保存在b数组
for (int j = 0; j < n; ++j) a[j] = (a[j] + fz * c[j]) % mod;
}
}
LL cal(LL k) { //计算第x=k值
LL ans = 0;
LL res = 1;
for (int i = 0; i < n; ++i) {
ans = (ans + res * a[i]) % mod;
res = res * k % mod;
}
ans = (ans + mod) % mod;
return ans;
}