https://www.cnblogs.com/zwfymqz/p/10063039.html
覺得把zwfymqz大佬的博客粘上來就差不多了
本博客比較淺顯,適合入門粗學,具體深入的話就看 attack 大佬的博客(就是上面的鏈接)吧
拉格朗日的公式
首先拉格朗日插值法的公式附上:
$$A(k)=\sum_{i=1}^{n} y_i \prod_{j=1}^{n} \dfrac{k-x_j}{x_i-x_j}$$
這個式子給出來肯定是先懵。沒關系,誰看到這玩意兒不會懵呢?
拉格朗日的作用
解釋一下,拉格朗日插值就是給你 n+1 個點,然后讓你構造出一個符合這堆點練成的光滑圖像的 n 次函數
說人話,就是給你 n+1 個點,讓你構造出一個 n 次函數,使得這個函數的圖像經過坐標軸上的 n+1 個點。
那么上面式子里面的 $x_i$ 以及 $y_i$ 就是一個點的坐標啦!
拉格朗日的分析
然后你自己驗證一下就可以發現: 將原來的點帶進去, A 函數輸出的結果是符合這 n 個點的位置的。
為什么? 因為如果你帶的點是 i 的話,那么當 $\sum$ 做到第 i 次時,后面的 $\prod$ 算出來的是 1 ,$\sum$的其余項都是 0
於是原式成立了,我們也可以拿它來計算別的 k 的函數值了
拉格朗日題的套路
至於這玩意兒拿來出題,無非就是裸題:
給你 n 個點以及正整數 k ,讓你用 n 個點求一個函數圖像並將 k 帶入求值(當然不是真要你求出函數圖像,輸出答案就好了)
這種題目的做法要么就是暴力代入公式,$O(n^2)$ ,要么給你的 n 個點的橫坐標是連續的,你可以利用這個性質優化到 $O(n)$ ,至於怎么優化嘛,想想階乘之類的東西...(具體推導你可以考慮打開文頭的鏈接)
至於另一種題型就是讓你求 $\sum_{i=1}^{n}i^k$ 的值了,這個東西為什么能用拉格朗日?他和上面講的東西毫無關聯啊!(你問我我問誰...)總之記好這玩意兒可以表示成一個 k+1 次多項式,然后就用 n 的值拿進去代就好了
做法么,自然就是枚舉出前 k+2 個點,然后看看 n 是否大於 k+2,不大於的話直接出解了,大於的話就是用 k+2 個點跑拉格朗日,n 帶入就好了。 並且由於這 k+2 個點的橫坐標是連續的,你可以將計算優化到 $O(k)$
什么?為什么這 k 個點是連續的? woc 這幾個點是你自己選出來的前 k+2 個點啊!
但最后還是決定解釋一下為什么 $A(n)=\sum_{i=1}^{n}i^k$ 這玩意兒可以表示成一個 k+1 次函數
怎么說,我們考慮將 $i^k$ 表示為 $n-(n-i)^k$ ,懂了吧,將 $n-i$ 看做常數(況且 $n-i$ 在這個表達式中本來就是連續的數)然后展開一下就是一個 k 次多項式啦!
恩? k 次? 不是 k+1 次么? emmm 我們考慮一下這里 $n^k$ 的項其實總共有 n 項,加起來可不就是 $n*n^k=n^{k+1}$ 么? 至於剩下的項次也是可以以此類推的...
(有興趣的讀者可以算一下哦,畢竟博主沒有算過,算出來piapia 打臉的話還請讀者在評論區中指出,但就算剩下的項無法整合成高一階的項,這里多項式的最高次系數也已經是 k+1 ,滿足 k+1 次函數的定義了)
神奇的重心拉格朗日
然后是某種騷操作,我是搞不大懂,拉格朗日前面加了個重心,說是優化,然后又說每加一個點的復雜度是 $O (n)$ 的(那加 n 個點的復雜度不還是 $n^2$ ?),也不知道真的假的...貌似真的
具體到圖像上的實現的話有一個動圖可以說明(不知道放到cnblogs上能不能動起來):
怎么說呢...就是慢慢找點唄...
然后就 完 了 _(:з」∠)_
慢着?板子都不放一個的?
$$O(n^2)$$
1 //by Judge 2 //by young Judge 3 #include<iostream> 4 #include<cstdio> 5 #define ll long long 6 using namespace std; 7 const int M=2111; 8 const ll mod=998244353; 9 #ifndef Judge 10 #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 11 #endif 12 char buf[1<<21],*p1=buf,*p2=buf; 13 inline ll read(){ 14 ll x=0,f=1; char c=getchar(); 15 for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; 16 for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; 17 } int n; ll k,K,ans,x[M],y[M]; 18 inline void AMOD(ll& a,ll& b){ a+=b; if(a>=mod) a%=mod; } 19 inline ll quick_pow(ll x,ll p,ll ans=1){ 20 while(p){ 21 if(p&1) ans=ans*x%mod; 22 x=x*x%mod,p>>=1; 23 } return ans; 24 } 25 int main(){ 26 n=read(),K=read(); 27 for(int i=1;i<=n;++i) x[i]=read(),y[i]=read(); 28 for(int i=1,j;i<=n;++i){ k=1; 29 for(j=1;j<=n;++j) if(i!=j) 30 k=k*(x[i]+mod-x[j])%mod; 31 k=quick_pow(k,mod-2); 32 for(j=1;j<=n;++j) if(i!=j) 33 k=k*(K+mod-x[j])%mod; 34 k=k*y[i]%mod,AMOD(ans,k); 35 } return printf("%lld\n",ans),0; 36 }
$$O(n)$$
1 //by Judge 2 #include<iostream> 3 #include<cstdio> 4 #define ll long long 5 using namespace std; 6 const int M=2111; 7 const ll mod=998244353; 8 #ifndef Judge 9 #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 10 #endif 11 char buf[1<<21],*p1=buf,*p2=buf; 12 inline ll read(){ 13 ll x=0,f=1; char c=getchar(); 14 for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; 15 for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; 16 } ll n,K,ans,x[M],y[M],s1[M],s2[M],ifac[M]; 17 inline void ADD(ll& a,ll b){ a+=b; if(a>=mod) a%=mod; } 18 int main(){ n=read()-1,K=read(),s2[n+1]=ifac[0]=ifac[1]=1; 19 for(int i=0;i<=n;++i) x[i]=read(),y[i]=read(); s1[0]=(K-x[i])%mod; 20 for(int i=1;i<=n;++i) s1[i]=s1[i-1]*(K-x[i])%mod; 21 for(int i=n;i>=1;--i) s2[i]=s2[i+1]*(K-x[i])%mod; 22 for(int i=2;i<=n;++i) ifac[i]=(mod-mod/i)*ifac[mod%i]%mod; 23 for(int i=2;i<=n;++i) ifac[i]=ifac[i]*ifac[i-1]%mod; 24 for(int i=0;i<=n;++i) 25 ADD(ans,1ll*y[i]*(i?s1[i-1]:1)%mod*s2[i+1]%mod* 26 ifac[i]%mod*((n-i&1)?-1:1)*ifac[n-i]%mod); 27 return !printf("%lld\n",(ans+mod)%mod); 28 }
什么?要函數封裝的?
1 ll lagrange(ll n,ll *x,ll *y,ll xi){ ll ans=0; 2 s1[0]=(xi-x[0])mod,s2[n+1]=ifac[0]=ifac[1]=1; 3 for(int i=1;i<=n;++i) s1[i]=s1[i-1]*(xi-x[i])%mod; 4 for(int i=n;i>=0;--i) s2[i]=s2[i+1]*(xi-x[i])%mod; 5 for(int i=2;i<=n;++i) ifac[i]=(mod-mod/i)*ifac[mod%i]%mod; 6 for(int i=2;i<=n;++i) ifac[i]=ifac[i]*ifac[i-1]%mod; 7 for(int i=0;i<=n;++i) 8 ADD(ans,1ll*y[i]*(i?s1[i-1]:1)%mod*s2[i+1]%mod* 9 ifac[i]%mod*((n-i&1)?-1:1)*ifac[n-i]%mod); 10 return (ans+mod)%mod; 11 }
數論的東西,不懂沒關系,看還是要看看的...