拉格朗日插值法 以2019南昌icpc B-Polynomial

拉格朗日插值法

拉格朗日插值法

对任意一个 x x x f ( x ) f(x) f(x)

给定一个 n n n次多项式(共有 n + 1 n+1 n+1项)
f ( x ) = a 0 + a 1 x + a 2 x 2 + ⋯ + a n x n f(x)=a_{0}+a_{1}x+a_{2}x^2+\cdots+a_{n}x^n f(x)=a0+a1x+a2x2++anxn

对于函数,若已知其任意 n + 1 n+1 n+1个x的取值以及其所对应的 f ( x ) f(x) f(x)(即为 y y y),可以利用拉格朗日插值来求其他任意 X X X f ( X ) f(X) f(X)

f ( X ) = L ( X ) = ∑ i = 0 n y i ∗ l i ( x ) = ∑ i = 0 n y i ∗ ∏ j ≠ j j &lt; = n X − x j x i − x j f(X)=L(X)=\sum_{i=0}^{n}y_{i}*l{i}(x)=\sum_{i=0}^{n}y_{i}*\prod_{j\neq j}^{j&lt;=n}\frac{X-x_{j}}{x_{i}-x_{j}} f(X)=L(X)=i=0nyili(x)=i=0nyij̸=jj<=nxixjXxj

f ( 1 ) = 1 , f ( 2 ) = 4 , f ( 3 ) = 9 f(1)=1,f(2)=4,f(3)=9 f(1)=1,f(2)=4,f(3)=9为例
l 1 ( x ) = x − 2 1 − 2 ∗ x − 3 1 − 3 l_{1}(x)=\frac{x-2}{1-2}*\frac{x-3}{1-3} l1(x)=12x213x3 l 2 ( x ) = x − 1 2 − 1 ∗ x − 3 2 − 3 l_{2}(x)=\frac{x-1}{2-1}*\frac{x-3}{2-3} l2(x)=21x123x3 l 3 ( x ) = x − 1 3 − 1 ∗ x − 2 3 − 2 l_{3}(x)=\frac{x-1}{3-1}*\frac{x-2}{3-2} l3(x)=31x132x2
f ( X ) = f ( 1 ) ∗ l 1 ( X ) + f ( 2 ) ∗ l 2 ( x ) + f ( 3 ) ∗ l 3 ( x ) f(X)=f(1)*l_{1}(X)+f(2)*l_{2}(x)+f(3)*l_{3}(x) f(X)=f(1)l1(X)+f(2)l2(x)+f(3)l3(x) = 1 ∗ x − 2 1 − 2 ∗ x − 3 1 − 3 + 4 ∗ x − 1 2 − 1 ∗ x − 3 2 − 3 + 9 ∗ x − 1 3 − 1 ∗ x − 2 3 − 2 =1*\frac{x-2}{1-2}*\frac{x-3}{1-3}+4*\frac{x-1}{2-1}*\frac{x-3}{2-3}+9*\frac{x-1}{3-1}*\frac{x-2}{3-2} =112x213x3+421x123x3+931x132x2 = x 2 =x^2 =x2
带入公式对于任意一个x是 O ( n ) O(n) O(n)的,多次询问即为 O ( n 2 ) O(n^2) O(n2)

已知 f ( x ) f(x) f(x)为连续的求 f ( n ) f(n) f(n)

l 0 ( x ) = ( x − 1 ) ( x − 2 ) ⋯ ( x − n ) ( 0 − 1 ) ( 0 − 2 ) ⋯ ( 0 − n ) l_{0}(x)=\frac{(x-1)(x-2)\cdots(x-n)}{(0-1)(0-2)\cdots(0-n)} l0(x)=(01)(02)(0n)(x1)(x2)(xn) l 1 ( x ) = ( x − 0 ) ( x − 2 ) ⋯ ( x − n ) ( 1 − 0 ) ( 1 − 2 ) ⋯ ( 0 − n ) l_{1}(x)=\frac{(x-0)(x-2)\cdots(x-n)}{(1-0)(1-2)\cdots(0-n)} l1(x)=(10)(12)(0n)(x0)(x2)(xn) ⋯ ⋯ \cdots\cdots l n ( x ) = ( x − 0 ) ( x − 1 ) ⋯ ( x − ( n − 1 ) ) ( n − 0 ) ( n − 1 ) ⋯ ( n − ( n − 1 ) ) l_{n}(x)=\frac{(x-0)(x-1)\cdots(x-(n-1))}{(n-0)(n-1)\cdots(n-(n-1))} ln(x)=(n0)(n1)(n(n1))(x0)(x1)(x(n1))

分子
M = ( x − 0 ) ( x − 1 ) ( x − 2 ) ⋯ ( x − n ) M=(x-0)(x-1)(x-2)\cdots(x-n) M=(x0)(x1)(x2)(xn)
l i ( x ) l_{i}(x) li(x)的分子为 M / ( x − i ) M/(x-i) M/(xi)

分母
l 0 ( x ) − &gt; ( − 1 ) n ∗ 0 ! ∗ n ! l_{0}(x)-&gt;(-1)^n*0!*n! l0(x)>(1)n0!n! l 1 ( x ) − &gt; ( − 1 ) n − 1 ∗ 1 ! ∗ ( n − 1 ) ! l_{1}(x)-&gt;(-1)^{n-1}*1!*(n-1)! l1(x)>(1)n11!(n1)! l 2 ( x ) − &gt; ( − 1 ) n − 2 ∗ 2 ! ∗ ( n − 2 ) ! l_{2}(x)-&gt;(-1)^{n-2}*2!*(n-2)! l2(x)>(1)n22!(n2)!
分母为: ( − 1 ) n − i ∗ i ! ∗ ( n − i ) ! (-1)^{n-i}*i!*(n-i)! (1)nii!(ni)!

n!的逆元
先用费马小定理求出 n ! n! n!的逆元
1 ( n − 1 ) ! = 1 n ! ∗ n m o d &ThinSpace;&ThinSpace; m o d \frac{1}{(n-1)!}=\frac{1}{n!}*n\mod mod (n1)!1=n!1nmodmod

Polynomial

题意

已知 f ( x ) = a 0 + a 1 x + a 2 x 2 + ⋯ + a n n f(x)=a_{0}+a_{1}x+a_{2}x^2+\cdots+a_{n}^n f(x)=a0+a1x+a2x2++ann
你知道 f ( 0 ) , f ( 1 ) , f ( 2 ) , ⋯ &ThinSpace; , f ( n ) f(0),f(1),f(2),\cdots,f(n) f(0),f(1),f(2),,f(n)
∑ i = L R f ( i ) \sum_{i=L}^{R}f(i) i=LRf(i)

分析

已知
f ( 0 ) = a 0 + a 1 0 + a 2 0 2 + ⋯ + a n 0 n f(0)=a_{0}+a_{1}0+a_{2}0^2+\cdots+a_{n}0^n f(0)=a0+a10+a202++an0n f ( 1 ) = a 0 + a 1 1 + a 2 1 2 + ⋯ + a n 1 n f(1)=a_{0}+a_{1}1+a_{2}1^2+\cdots+a_{n}1^n f(1)=a0+a11+a212++an1n f ( 2 ) = a 0 + a 1 2 + a 2 2 2 + ⋯ + a n 2 n f(2)=a_{0}+a_{1}2+a_{2}2^2+\cdots+a_{n}2^n f(2)=a0+a12+a222++an2n ⋯ ⋯ \cdots\cdots f ( n ) = a 0 + a 1 n + a 2 n 2 + ⋯ + a n n n f(n)=a_{0}+a_{1}n+a_{2}n^2+\cdots+a_{n}n^n f(n)=a0+a1n+a2n2++annn

显然,对 1 n + 2 n + 3 n + ⋯ + x n = b 0 x n + 1 1^n+2^n+3^n+\cdots+x^n=b_{0}x^{n+1} 1n+2n+3n++xn=b0xn+1

S ( n ) = ∑ i = 1 n f ( i ) = b 0 + b 1 n + b 2 n 2 + ⋯ + b n n n + b n + 1 n n + 1 S(n)=\sum_{i=1}^{n} f(i)=b_{0}+b_{1}n+b_{2}n^2+\cdots+b_{n}n^n+b_{n+1}n^{n+1} S(n)=i=1nf(i)=b0+b1n+b2n2++bnnn+bn+1nn+1

先用拉格朗日插值推出 a n + 1 a_{n+1} an+1,再推出 S ( 0 ) , S ( 1 ) , ⋯ &ThinSpace; , S ( n ) , S ( n + 1 ) S(0),S(1),\cdots,S(n),S(n+1) S(0),S(1),,S(n),S(n+1)
再用拉格朗日插值推出 S ( R ) − S ( L − 1 ) S(R)-S(L-1) S(R)S(L1)

代码

预处理

fac[0] = 1;		//阶乘
for (int i = 1; i <= maxn; i++)
	fac[i] = fac[i] * i % mod;
inv[1] = 1;		//逆元
for (int i = 2; i <= maxn; i++) 
	inv[i] = (mod - mod / i) * (LL)1 * inv[mod % i] % mod;
fac_inv[maxn] = quickpow(fac_inv[maxn], mod - 2);	//n!的逆元
for (int i = maxn - 1; i >= 1; i--)
	fac_inv[i] = fac_inv[i + 1] * (i + 1) % mod;

拉格朗日插值 f ( n + 1 ) f(n+1) f(n+1)

void Get_f_next() {		//计算a[n+1]
	f[n + 1] = 0;
	LL M = 1;		//处理分子
	for (int i = 0; i <= n; i++)
		M = M * (n + 1 - i) % mod;
	LL ans = 0;		//拉格朗日插值
	for (int i = 0; i <= n; i++) {
		ans = M * inv[n + 1 - i] % mod		//分子
			* fac_inv[n-i] % mod * fac_inv[i] % mod; //分母
		if ((n - i) & 1)f[n + 1] = (f[n + 1] - ans * f[i] % mod + mod) % mod;	//yi*li
		else f[n + 1] = (f[n + 1] + ans * f[i] % mod + mod) % mod;
	}
}

拉格朗日插值 S ( r ) S(r) S(r)

LL Get_S(LL r) {
	if (r <= n + 1)
		return sum[r];
	LL M = 1;
	for (int i = 0; i <= n + 1; i++)	//处理分子
		M = M * LL(r - i) % mod;			//分母
	LL ans = 0, res = 0;
	for (int i = 0; i <= n + 1; i++) {
		ans = M * inv[r - i] % mod //分子
			* fac_inv[n + 1 - i] % mod * fac_inv[i] % mod;	//分母
		if ((n + 1 - i) & 1) res = (res - ans * sum[i] % mod + mod) % mod;	//yi*li
		else res = (res + ans * sum[i] % mod + mod) % mod;
	}
	return res;
}

完整代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
const int maxn = 1005;
const LL mod = 9999991;
LL fac[maxn + 5], inv[mod + 100], fac_inv[maxn + 5];
LL quickpow(LL m, LL p) {
	LL res = 1;
	while (p) {
		if (p & 1) 
			res = res * m % mod;
		m = m * m % mod;
		p >>= 1;
	}
	return res;
}
void init() {
	fac[0] = 1;
	for (int i = 1; i <= maxn; i++)
		fac[i] = fac[i - 1] * LL(i) % mod;
	fac_inv[maxn] = quickpow(fac[maxn], mod - 2);
	for (int i = maxn - 1; i >= 0; i--)
		fac_inv[i] = fac_inv[i + 1] * (LL(i) + 1) % mod;
	inv[0] = inv[1] = 1;
	for (int i = 2; i < mod+5; i++)
		inv[i] = (mod - mod / i) * (LL)1 * inv[mod % i] % mod;
}
LL t, n, m;
LL f[maxn], sum[maxn];
void Get_f_next() {		//计算a[n+1]
	f[n + 1] = 0;
	LL M = 1;		//处理分子
	for (int i = 0; i <= n; i++)
		M = M * (n + 1 - i) % mod;
	LL ans = 0;		//拉格朗日插值
	for (int i = 0; i <= n; i++) {
		ans = M * inv[n + 1 - i] % mod		//分子
			* fac_inv[n-i] % mod * fac_inv[i] % mod; //分母
		if ((n - i) & 1)f[n + 1] = (f[n + 1] - ans * f[i] % mod + mod) % mod;	//yi*li
		else f[n + 1] = (f[n + 1] + ans * f[i] % mod + mod) % mod;
	}
}
LL Get_S(LL r) {
	if (r <= n + 1)
		return sum[r];
	LL M = 1;
	for (int i = 0; i <= n + 1; i++)	//处理分子
		M = M * LL(r - i) % mod;			//分母
	LL ans = 0, res = 0;
	for (int i = 0; i <= n + 1; i++) {
		ans = M * inv[r - i] % mod //分子
			* fac_inv[n + 1 - i] % mod * fac_inv[i] % mod;	//分母
		if ((n + 1 - i) & 1) res = (res - ans * sum[i] % mod + mod) % mod;	//yi*li
		else res = (res + ans * sum[i] % mod + mod) % mod;
	}
	return res;
}
int main() {
	init();
	scanf("%lld", &t);
	while (t--) {
		scanf("%lld%lld", &n, &m);
		for (int i = 0; i <= n; i++) {
			cin >> f[i]; f[i] %= mod;
		}
		Get_f_next();
		sum[0] = f[0];
		for (int i = 1; i <= n + 1; i++)
			sum[i] = (sum[i - 1] + f[i]) % mod;
		LL l, r;
		while (m--) {
			scanf("%lld%lld", &l, &r);
			printf("%lld\n", (Get_S(r) - Get_S(l - 1) + mod) % mod);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值