【学习笔记】拉格朗日插值

【学习笔记】拉格朗日插值

介绍

拉格朗日插值是用来求高次多项式的一种方法。我们知道假设已经给定了 n 个点,那么一定会有一个唯一确定的 n1 次的多项式,拉格朗日插值就是用来求这样的多项式的。

实现

给出拉格朗日插值的式子,假设已经给定了 n 个点,分别为 xi,yi,(1in) 那么

fx=i=1nyij=1,jinxxjxixj

可以发现,对于第 i 项,如果 xxi 则值为 yi,否则为 0。因此把 xi 带入可得 fxi=yi。暴力求解时间复杂度 O(n2)

The Sum of the k-th Powers

思路

首先证明一个结论:对于一个通项公式为 k 次的数列 {an},每进行一次差分,生成新序列的通项公式的最高次数就会减 1
首先设序列的通项公式为 i=1kui×xi,其中 u 为系数,则他的一阶差分的通项公式为

fx+1fx=i=1kui×((x+1)ixi)

将其用二项式定理拆开,然后发现 xkxk=0 所以最高次项约没了,因此得证。
回到题目,当前数列的通项公式为 i=1xik,他的一阶差分的通项公式为

i=1x+1iki=1xik=(x+1)k

发现是一个 k 次式,所以原始数列的通项公式为 k+1 次。
所以我们可以先构造 k+2 个点(直接暴力构造就行),然后使用拉格朗日插值。
考虑到基本公式 fx=i=1nyij=1,jinxxjxixj, 发现 xj,xi 都是连续的,所以

  • 分母上为 xi1×xi2...×1×1...×xi(k+2),发现为 (xi1)!×(k+2xi)!
    注意需要判断符号如果 (kxi+2) 如果为奇数需要再乘 1
  • 分子用一个前后缀维护就行。

code

#include<bits/stdc++.h>
#define N 1000010
#define int long long
#define mod 1000000007
using namespace std;
int n, k, pre[N], suc[N], frac[N], y = 0, ans = 0;
int fast(int a, int p){
	int s = 1;
	while(p){
		if(p & 1) s = s * a % mod;
		a = a * a % mod;
		p = p >> 1;
	}
	//cout << s << endl;
	return s; 
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n >> k;
	pre[0] = 1ll, suc[k + 3] = 1ll, frac[0] = 1ll;
	for(int i = 1; i <= k + 2; i++) frac[i] = frac[i - 1] * i % mod;
	for(int i = 1; i <= k + 2; i++) pre[i] = pre[i - 1] * (n - i) % mod;
	for(int i = k + 2; i >= 1; i--) suc[i] = suc[i + 1] * (n - i) % mod;
	for(int i = 1; i <= k + 2; i++){
		y = (y + fast(i, k)) % mod;
		int a = pre[i - 1] * suc[i + 1] % mod;
		int b = frac[i - 1] * frac[k + 2 - i] % mod  * ((k - i) & 1 ? -1ll : 1ll) % mod;
		ans = (ans + a % mod * fast(b, mod - 2) % mod * y % mod) % mod;
	}
	cout << (ans + mod) % mod;
	return 0;
}
``cpp
posted @   GuoSN0410  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示