Loading

学习笔记 多项式

基础知识

拉格朗日插值法

给你n个点\((x_1,y_1),(x_2,y_2),...\)

求一个n-1次的多项式\(f(x)\),求\(f(k)\)

我们可以认为\(f(x)=f_1(x)+f_2(x)+..+f_{n+1}(x)\)

其中\(f_i(x_i)=y_i\)\(\forall j\neq i,f_i(x_j)=0\)

也就是说一个点\(x_i\)只在一个函数中为\(y_i\),其他函数中均为0

换言之就是把多条曲线合在一起(跟CRT的构造思想一致)

然后我们很容易构造以上式子

\[f(x)=\sum_{i=1}^{n}y_i\Pi_{j\neq i}\frac{x-x_j}{x_i-x_j} \]

重心拉格朗日插值法

\[f(x)=\sum_{i=1}^{n}y_i\Pi_{j\neq i}\frac{x-x_j}{x_i-x_j} \]

\[g(x)=\Pi_{i=1}^{n}x-x_i \]

\[h(i)=\frac{y_i}{\Pi_{j!=i}x_i-x_j} \]

那么

\[f(x)=g(x)\sum_{i=1}^{n}\frac{h(i)}{x-x_i} \]

那么如果我们要修改单点的横坐标,就可以单独修改\(h(i),g(x)\)来解决,复杂度为\(O(n)\)

各种插值法的介绍


FFT && NTT

FFT

自为风月马前卒的FFT讲解

NTT

对于NTT,只是把N次复数单位根换成了原根

NTT素数表

Miskcoo


泰勒级数,泰勒公式,泰勒展开

泰勒函数的解释1

泰勒函数的解释2

“使用泰勒公式进行估算时,在不同点展开的区别和意义是啥?”的回答

多项式全家桶

miskcoo's

假设\(A(x)\)已知

多项式牛顿迭代

\(G(B(x))\equiv 0 \mod x^n\)

使用倍增法,设\(\frac{n}{2}\)项多项式\(B_0(x)\)满足\(G(B_0(x))\equiv 0 \mod x^{\frac{n}{2}}\)

泰勒展开一波

\[G(B(x))\equiv \frac{G(B_0(x))}{0!}+\frac{G^{'}(B_0(x))}{1!}(B(x)-B_0(x))+\frac{G^{''}(B_0(x))}{2!}(B(x)-B_0(x))^2··· (\mod x^n) \]

可知\(B(x)\)\(B_0(x)\)\(\frac{n}{2}\)项相同,所以\((B(x)-B_0(x))^k(k\ge 2)\)在模\(x^n\)意义下为0

所以

\[B(x)\equiv B_0(x)-\frac{G(B_0(x))}{G^{'}(B_0{x})} \]

多项式求逆

Miskcoo

假设我们已经推完了\(A(x)B_0(x)\equiv 1\mod x^{n}\)

要求\(A(x)B(x)\equiv 1\mod x^{2n}\)中的\(B(x)\)

\[\begin{aligned}A(x)(B(x)-B_0(x))=0 \mod x^{n}\\B(x)-B_0(x)\equiv0 \mod x^n\\B^2(x)-2B(x)B_0(x)+B_0^2(x)\equiv 0 \mod x^{2n}\\B(x)-2B_0(x)+A(x)B_0^2(x)\equiv 0 \mod x^{2n}\\B(x)\equiv B_0(x)(2-A(x)B_0(x)) \mod x^{2n}\end{aligned} \]

多项式ln/exp

ln

\[\begin{aligned}B(x)&\equiv\ln A(x) \mod x^n\\&\equiv\int\frac{A^{'}(x)}{A(x)}dx \mod x^n\end{aligned} \]

exp

\[\begin{aligned}B(x)\equiv e^{A(x)} \mod x^n \\ln B(x)-A(x)\equiv 0 \mod x^n \end{aligned} \]

\(G(B(x))=\ln B(x)-A(x)\) ,则\(G^{'}(B(x))=\frac{1}{B(x)}\),套牛顿迭代公式

\[\begin{aligned}B(x)&\equiv B_0(x)-\frac{\ln B_0(x)-A(x)}{\frac{1}{B_0(x)}}\\&\equiv B_0(x)(1-\ln B_0(x)+A(x))\end{aligned} \]

多项式开方

牛顿迭代得

\[B(x)=B_0(x)-\frac{B_0^2(x)-A(x)}{2B_0(x)} \]

多项式快速幂

\[\begin{aligned}B(x)&\equiv A^k(x)\\&\equiv e^{k\ln A(x) }\end{aligned} \]

时间复杂度\(O(nlogn)\)然而常数巨大

代码

int qpow(int x,int b){
	int ans=1,mul=x;
	while(b){
		if(b&1)ans=1ll*ans*mul%MOD;
		mul=1ll*mul*mul%MOD;
		b>>=1;
	}
	return ans;
}
void NTT(int *a,int Len,int type){
	for(int i=0;i<Len;i++)if(i<re[i])swap(a[i],a[re[i]]);
	for(int mid=1;mid<Len;mid<<=1){
		int Wn=qpow(type==1?gi:gf,(MOD-1)/(mid<<1));
		for(int l=0;l<Len;l+=(mid<<1)){
			int w=1;
			for(int k=0;k<mid;k++,w=1ll*w*Wn%MOD){
				int x=a[l+k],y=1ll*a[l+k+mid]*w%MOD;
				a[l+k]=(x+y)%MOD;a[l+k+mid]=(x-y+MOD)%MOD;
			}
		}
	}
	if(type==-1){
		int inv=qpow(Len,MOD-2);
		for(int i=0;i<Len;i++)a[i]=1ll*a[i]*inv%MOD;
	}
}
void Init(int n){
	for(Len=1,N=0;Len<=(n<<1);Len<<=1,N++);
	for(int i=0;i<Len;i++)re[i]=(re[i>>1]>>1)|((i&1)<<(N-1));
}
void get_Inv(int *f,int n,int *b){
	if(n==1){
		return b[0]=qpow(f[0],MOD-2),void();
	}
	get_Inv(f,(n+1)>>1,b);
	Init(n);
	for(int i=0;i<n;i++)a[i]=f[i];
	for(int i=n;i<Len;i++)a[i]=0;
	NTT(a,Len,1);NTT(b,Len,1);
	for(int i=0;i<Len;i++)b[i]=1ll*(2-1ll*a[i]*b[i]%MOD+MOD)%MOD*b[i]%MOD;
	NTT(b,Len,-1);
	for(int i=n;i<Len;i++)b[i]=0;
	return;
}
void get_Ln(int *f,int n,int *b){
	memset(inv,0,sizeof(inv));
	memset(la,0,sizeof(la));
	for(int i=0;i<=n-2;i++)la[i]=1ll*f[i+1]*(i+1)%MOD;//mis
	la[n-1]=0;
	get_Inv(f,n,inv);
	Init(n);
	NTT(la,Len,1);NTT(inv,Len,1);
	for(int i=0;i<Len;i++)b[i]=1ll*la[i]*inv[i]%MOD;
	NTT(b,Len,-1);
	for(int i=n-1;i>=1;i--)b[i]=1ll*b[i-1]*qpow(i,MOD-2)%MOD;//mis
	b[0]=0;
}
void get_Exp(int *f,int deg,int *b){
	if(deg==1)return b[0]=1,void();
	get_Exp(f,(deg+1)>>1,b);
	memset(ln,0,4*deg);
	memset(ea,0,4*deg);
	get_Ln(b,deg,ln);
	// for(int i=0;i<deg;i++)printf("%d ",ln[i]);
	// printf("\n");
	Init(deg);
	for(int i=0;i<deg;i++)ea[i]=f[i];
	for(int i=deg;i<Len;i++)ea[i]=0;
	NTT(ea,Len,1);NTT(b,Len,1);NTT(ln,Len,1);
	for(int i=0;i<Len;i++)b[i]=1ll*(1-ln[i]+ea[i]+MOD)%MOD*b[i]%MOD;
	NTT(b,Len,-1);
	for(int i=deg;i<Len;i++)b[i]=0;
}
void get_Pow(int *f,int deg,int k,int *b){
	for(int i=0;i<deg;i++)pa[i]=f[i];
	get_Ln(pa,deg,pa);
	for(int i=0;i<deg;i++)pa[i]=1ll*pa[i]*k%MOD;
	get_Exp(pa,deg,b);
}
void get_Sqrt(int *f,int n,int *b){
	if(n==1)return b[0]=1,void();
	get_Sqrt(f,(n+1)>>1,b);
	memset(inv,0,sizeof(inv));
	get_Inv(b,n,inv);
	Init(n);
	for(int i=0;i<n;i++)sa[i]=f[i];
	for(int i=n;i<Len;i++)sa[i]=0;
	NTT(sa,1);NTT(inv,1);
	for(int i=0;i<Len;i++)
		sa[i]=1ll*sa[i]*inv[i]%MOD;
	NTT(sa,-1);
	for(int i=0;i<Len;i++)b[i]=1ll*qpow(2,MOD-2)*(b[i]+sa[i])%MOD;
	for(int i=n;i<Len;i++)b[i]=0;
}

多项式除法

多项式多点插值/求值

posted @ 2021-02-03 15:20  fpjo  阅读(109)  评论(0编辑  收藏  举报