update:其實拉格朗日插值法的問題在於求分母的複雜度是 \(o(n^2)\) 的,要是還要求逆元則再多乙個 \(logp\) 變成 \(o(n^2logp)\),但是當乙個多項式要重複使用的時候,也不必求出他的各個係數,只要預處理出各項分母的逆元之後,\(o(nlogp)\) 處理分子(求出字首積和字尾積),然後再插值,漸進複雜度和求出係數值的一樣。當分母是等差數列之類的有規律的東西,他的分母可能是可以更快求出的。
參考資料:
因為高斯消元法是n立方的,有些鬼畜問題需要n平方的拉格朗日插值法。
使用逆元的n平方logn預處理,nlogn單次詢問的重心拉格朗日插值法:
(假如使用double的話,理論上預處理和詢問都少個log)
通過n個不同的點直接構造出多項式。#includeusing namespace std;
typedef long long ll;
namespace lagrange_interpolation_polynomial
return ans;
}void init_xi_xj()}}
for(int i=1;i<=n;i++)}}
void init_k(int k)
}inline int prod(int i,int k)
int lagrange(int k)
return ans;
}}using namespace lagrange_interpolation_polynomial;
int main()
init_xi_xj();
printf("%d\n",lagrange(k));
}
$f(x)=\sum\limits_^ y_i \prod\limits_\frac $
正確性:代入 \(x_i\) 只有 \(y_i\) 右邊是1,其他分子都有0,消掉了。
那麼可以n平方構造。
需要小心溢位以及卡常數。假如進行同乙個多項式的多次求 \(f(k)\) 的值 ,\(x_i-x_j\) 的逆元需要多次使用,可以像下面的類似做法預處理他們的差,當然kd和pkd要重新處理。不需要用map存,這樣和直接求qpow乙個鬼樣。
開個invd陣列,儲存每兩個項之間的差的逆元。
注意到prod裡面有一項是 \(k-x_j\) 的積,這裡也可以選擇直接記錄這個積。畢竟模運算比較費時,卡出來的常數可能差幾倍
因為是要求逆元的,所以預處理 \(o(n^2logn)\) 。
然後每次求新k時,預處理重心拉格朗日插值法的g, \(o(nlogn)\) 。
多次求同一多項式的值快了不少的,比原版的拉格朗日插值。就是要 \(o(n^2)\) 的額外空間。
先卡掉重複求差的逆元的,已經可以通過了。
#includeusing namespace std;
typedef long long ll;
const int mod=998244353;
int n,x[2005],y[2005];
int qpow(int x,int n)
return ans;
}int invd[2005][2005];
int kd[2005];
void init_prod(int k)
return ans;
}int invd[2005][2005];
int kd[2005],pkd;
void init_prod(int k)
return ans;
}void init_xi_xj()}}
for(int i=1;i<=n;i++)}}
void init_k(int k)
}inline int prod(int i,int k)
int lagrange(int k)
return ans;
}}using namespace lagrange_interpolation_polynomial;
ll jury(ll x) ;
ll ret=0;
ll tx=1;
for(int i=0; i<=10; i++)
//cout<<"jury: "《一般我們代入的點都是連續自然數,當 \(x_i\) 的取值是連續自然數時,插值法因為分母變得容易處理而變成n複雜度。
以從0開始取舉例。
假設當前n為4,從1開始取。其實分子無論怎麼取值都是可以用字首積和字尾積預處理出來的,然後兩段乘在一起。關鍵是分母,當分母是連續自然數的時候不必兩兩枚舉。
\(y_1\frac+y_2\frac+y_3\frac+y_4\frac\)
分母是:\(1*(-1)(-2)(-3),(1)*(-1)*(-2),(2)(1)*(-1),(3)(2)(1)\)
也就是前面階乘,後面是負數的階乘,負數的階乘也很好想,比如這裡n=4,那麼第一項有3個負數,階乘為負數,第二項為正數,第三項為負數……也就是n-i為奇數的項是負數。
可不斷插點的重心拉格朗日插值法。
原式$f(x)=\sum\limits_^ y_i \prod\limits_\frac $
把分子補上缺的項,提出來,記 \(g=\prod\limits_^ x-x_i\)
$f(x)=g\sum\limits_^ \frac \prod\limits_\frac $
再記 \(h_i= \prod\limits_\frac\)
$f(x)=g\sum\limits_^ \frac $
那麼每次多加乙個點的時候,更新 \(g\) 以及每乙個 \(h_i\) 就可以了。
經典例題:求 $\sum\limits_^ i^k $ n很大但k只有幾千萬(需要連續字首優化)
推出計算式之後,就是計算上面那個東西。注意步驟,首先要確定多項式的係數,乙個k次多項式的和一般都是k+1次的,這裡是m+1次多項式的和,也就是m+2次多項式,需要m+3個點。
注意用拉格朗日插值時,判斷k與x_i不重複再插,不然返回y_i就可以了。
#includeusing namespace std;
typedef long long ll;
const int mod=1e9+7;
namespace lagrange_interpolation_polynomial
return ans;
}void init_xi_xj()}}
for(int i=1;i<=n;i++)
//cout<<"pinvd["int main()
n-=vm[0];
vm=tv;
}cout<}
}
拉格朗日插值法
拉格朗日插值法 拉格朗日插值法可以幫助我們解決以下的問題 已知x取值0,1,1,2時,f取值2,2,0,6 求x 3時f的值。示例1 intxs intys f 3 intval lagrangepolynomial 3,xs,ys staticint lagrangepolynomial intx...
拉格朗日插值法
模板題 給出n nn個點 xi yi x i,y i xi y i 讓你確定這個n 1 n 1n 1次方程並代入求值 這個有三種求法 第一種是差分法,只適用於xi ix i i xi i的情況,就是不斷做差分直到序列變成乙個定值就可以求出所有項的係數,複雜度o n 2 o n 2 o n2 第二種是...
拉格朗日插值法
function p lagrange x,y p lagrange x,y 其中x和y是向量,p是返回的多項式向量 m獲取x的個數 m length x for k 1 1 m 表示乙個插值函式的起始值 v 1 for i 1 1 m if k i 注意 以後凡是在遇到乙個在數學上是 x 1 等包...