1. 程式人生 > >【拉格朗日插值法】

【拉格朗日插值法】

對某個多項式函式,已知有給定的k + 1個取值點:

(x0,y0),,(xk,yk)

其中xj對應著自變數的位置,而yj對應著函式在這個位置的取值。

假設任意兩個不同的xj都互不相同,那麼應用拉格朗日插值公式所得到的拉格朗日插值多項式為:

L(x):=j=0kyjj(x)

其中每個j(x)為拉格朗日基本多項式(或稱插值基函式),其表示式為:

j(x):=i=0,ijkxxixjxi=(xx0)(xjx0)(xxj1)(xjxj1)(xxj+1)(xjxj+1)(xxk)(xjxk)

拉格朗日基本多項式j(x)的特點是在xj上取值為1,在其它的點xi,ij上取值為0。

程式碼

//1.先呼叫 init(n)初始化 逆元陣列。
//2.估計出答案的最高次數,然後構造一個比最高次數多一項的插基陣列。
//3.然後呼叫polyval求第n項。
typedef long long LL;
const int MOD=1e9+7;
const int N=1020;
LL pod(LL x
,LL n) { LL ret=1; while(n) { if(n&1)ret=ret*x%MOD; n>>=1; x=x*x%MOD; } return ret; } namespace Polyval { LL fac[N],invv[N],p1[N],p2[N]; void init(int n) { fac[0]=fac[1]=invv[0]=invv[1]=1; for(int i=2; i<=n; i++) fac[i]=fac[i-1]*i
%MOD; invv[n]=pod(fac[n],MOD-2); for(int i=n; i>1; i--) invv[i-1]=invv[i]*i%MOD; } LL polyval(int d,LL *a,LL n) { if(n<=d)return a[n]; p1[0]=1; p2[d]=1; for(LL i=0; i<=d; i++) p1[i+1]=p1[i]*(n-i)%MOD; for(LL i=d; i>0; i--) p2[i-1]=p2[i]*(n-i)%MOD; LL ans=0; for(int i=0; i<=d; i++) { LL tem=a[i]*p1[i]%MOD*p2[i]%MOD*invv[i]%MOD*invv[d-i]%MOD; cout<<tem<<endl; if((d-i)&1)ans=(ans-tem+MOD)%MOD; else ans=(ans+tem)%MOD; } ans=(ans+MOD)%MOD; return ans; } } LL b[N],a[N]; //求k次方的前n項和 int main() { int n,k; Polyval::init(1010); while(scanf("%d%d",&n,&k)!=EOF) { b[0]=0; for(LL i=1;i<=k+1;i++) //和最高為k+1項 { b[i]=(pod(i,k)+b[i-1])%MOD; //構造和的k+2個點 } printf("%lld\n",Polyval::polyval(k+1,b,n)); } }

杜教模板