将我隐藏,成为星空中崭新的孤岛|

cc0000

园龄:5年1个月粉丝:14关注:5

多项式笔记

多项式,清空,封装,边界,是讨厌的。

目录

其实我不会做目录。

现已加入(按加入时间排序):

  • NTT
  • 多项式求逆
  • 多项式对数函数
  • 多项式指数函数
  • 泰勒展开,牛顿迭代
  • 多项式除法
  • 多项式快速幂
  • 多项式开根

然后还有的东西会慢慢加(好困

预知识

背下来

泰勒展开

f(x)=i=0f(i)(0)i!xi

f(x)=i=0f(i)(a)i!(xa)i

我不会不敢乱讲

大概的意思是用多项式来拟合一些不好求的函数。应用就是下面的牛顿迭代。

牛顿迭代

已知 g(f0(x))0(modxn2)

求解 g(f(x))0(modxn)

结论: f(x)=f0(x)g(f0(x))g(f0(x))

证明:

首先使用泰勒展开,将 g(f(x))f0(x) 处展开

得到 g(f(x))=i0g(i)(f0(i))i!(f(x)f0(x))i

由于 f(x)f0(x)0(modx)n2

所以在 i2 的情况下,(f(x)fi(x))i0(modxn)

所以原式展开: g(f(x))=g(f0(x))+g(f0(x))(f(x)f0(x))

化简一下即可得到 f(x)=f0(x)g(f0(x))g(f0(x))

导数相关小知识

(F(x)+G(x))=F(x)+G(x)

(cF(x))=cF(x) (c 为常数)

(xk)=kxk1

(lnx)=1x

(ex)=ex

(ax)=axlna

(F(x)G(x))=F(x)G(x)+G(x)F(x)

(F(x)G(x))=F(x)G(x)+F(x)G(x)G2(x)

(F(G(x)))=F(x)G(F(x))

NTT

懒得讲原理,喵。

	ll A[maxn],B[maxn],pos[maxn],S[maxn];
	const int mod=998244353,g=3,ginv=332748118;
	ll ksm(ll x,int y)
	{
		ll ret=1;
		while(y)
		{
			if(y&1) ret=ret*x%mod; 
			x=x*x%mod; y>>=1;
		}
		return ret;
	}
	int pre(int n,int m)
	{
		int lim=0;
		while((1<<lim)<=n+m) lim++;
		for(int i=0;i<=(1<<lim);i++)
				pos[i]=(pos[i>>1]>>1)|((i&1)<<(lim-1));
		return lim;
	}
	void NTT(ll *f,ll n,int opt)
	{
		for(int i=0;i<n;i++) if(i<pos[i]) swap(f[i],f[pos[i]]);
		for(int i=1;i<n;i<<=1)
		{
			ll step=ksm((opt>0?g:ginv),(mod-1)/(2*i));
			for(int j=0;j<n;j+=i+i)
			{
				ll cur=1;
				for(int k=j;k<j+i;k++)
				{
					int gx=f[k],hx=1ll*cur*f[k+i]%mod;
					f[k]=(gx+hx)%mod;f[k+i]=(gx-hx+mod)%mod;
					cur=cur*step%mod;
				}
			}
		}
		if(opt==-1)
		{
			int ninv=ksm(n,mod-2);
			for(int i=0;i<n;i++) f[i]=f[i]*ninv%mod;
		}
	}
	void MUL(ll *s,ll *f,ll *h,int n,int m)
	{
		int lim=pre(n,m);
		for(int i=0;i<=n;i++) A[i]=f[i];
		for(int i=0;i<=m;i++) B[i]=h[i];
		for(int i=n+1;i<=(1<<lim);i++) A[i]=0;
		for(int i=m+1;i<=(1<<lim);i++) B[i]=0;
		NTT(A,(1<<lim),1);NTT(B,(1<<lim),1);
		for(int i=0;i<=(1<<lim)-1;i++) s[i]=A[i]*B[i]%mod;
		NTT(s,(1<<lim),-1);
	}

多项式求逆

给出F(x),求出 G(x) 使得 G(x)F(x)1(modxn)

F(x)H(x)1(modxn2)

F(x)(G(X)H(x))0(modxn2)

G(x)H(x)0(modxn2)

(G(x)H(x))20(modxn)

G2(x)2G(x)H(x)+H2(x)0(modxn)

两边同时乘个 F(x)

G(x)2H(x)+F(x)H2(x)0(modxn)

G(x)=2H(x)F(x)H2(x)

然后已知 H(x) 就能做了。递归下去就行了。。

一般都写成非递归。

	void INV(ll *s,ll *f,int n)
	{
		S[0]=ksm(f[0],mod-2);S[1]=0;
		for(int len=2;len<=(n<<1);len<<=1)
		{
			ll lim=(len<<1);
			for(int i=0;i<len;i++) A[i]=f[i],B[i]=S[i];
			for(int i=len;i<lim;i++) A[i]=B[i]=0;
			pre(len,0);
			NTT(A,lim,1); NTT(B,lim,1);
			for(int j=0;j<lim;j++)
				S[j]=(2*B[j]%mod+mod-A[j]*B[j]%mod*B[j]%mod)%mod;
			NTT(S,lim,-1);
			for(int j=len;j<lim;j++) S[j]=0;
		}
		for(int i=0;i<=n;i++) s[i]=S[i];
	}

多项式对数函数(ln)

G(x)=ln(F(X))

同时求导

G(x)=ln(F(x))

然后复合函数求导拆开

G(x)=F(x)F(x)

然后先求导,再求逆,最后积分一下就行。

求导:(xα)=αxα1

积分:αxα1=xα

xα=1α+1xα+1

多项式指数函数(exp)

给出 f(x)g(x)ef(x)(modxn)

f(x)lng(x)

f(x)lng(x)0

h(t)=f(x)lnt,那么 h(g(x))0

h(g0(x))0(modxn2)

g(x)g0(x)f(g0(x))h(g0(x))

g0(x)f(x)lng0(x)1g0(x)

g0(x)g0(x)lng0(x)+g0(x)f(x)

g0(x)(1lng0(x)+f(x))

然后就能算了。

多项式除法

n 项多项式 f(x), 和 m 项多项式 g(x),求 nm 项的多项式 q(x),以及 m1 项的 r(x) ,满足 f(x)g(x)q(x)+r(x)

神奇的转化。

fr(x) 为把 f(x) 翻转过来后的多项式,一定有 fr(x)=f(x)xn

1n 代入上式,f(1n)g(1n)q(1n)+r(1n)

式子同时乘 xn,得到 fr(x)gr(x)qr(x)+rr(x)×xnm+1

然后 fr(x)gr(x)qr(x)(modxnm+1)

直接多项式求逆即可

多项式开根

已知 f(x) ,求 g2(x)f(x)(modxn)

f(x)g2(x)0(modxn)

h(t)=f(x)t2,h(g(x))0(modxn)

牛顿迭代,令 h(g0(x))0(modxn2)

g(x)g0(x)f(x)g02(x)2g0(x)

然后稍微化简一下,g(x)g0(x)+f(x)g0(x)2

多项式快速幂

已知 f(x)k ,求 g(x)fk(x)

同时取 lnlng(x)klnf(x)

g(x)=exp(klnf(x))

前提是 f(0)=1

全套模板(未完工)

namespace POLY
{
	ll A[maxn],B[maxn],pos[maxn],S[maxn];
	const int mod=998244353,g=3,ginv=332748118;
	ll ksm(ll x,int y)
	{
		ll ret=1;
		while(y)
		{
			if(y&1) ret=ret*x%mod; 
			x=x*x%mod; y>>=1;
		}
		return ret;
	}
	int pre(int n,int m)
	{
		int lim=0;
		while((1<<lim)<=n+m) lim++;
		for(int i=0;i<=(1<<lim);i++)
				pos[i]=(pos[i>>1]>>1)|((i&1)<<(lim-1));
		return lim;
	}
	void NTT(ll *f,ll n,int opt)
	{
		for(int i=0;i<n;i++) if(i<pos[i]) swap(f[i],f[pos[i]]);
		for(int i=1;i<n;i<<=1)
		{
			ll step=ksm((opt>0?g:ginv),(mod-1)/(2*i));
			for(int j=0;j<n;j+=i+i)
			{
				ll cur=1;
				for(int k=j;k<j+i;k++)
				{
					int gx=f[k],hx=1ll*cur*f[k+i]%mod;
					f[k]=(gx+hx)%mod;f[k+i]=(gx-hx+mod)%mod;
					cur=cur*step%mod;
				}
			}
		}
		if(opt==-1)
		{
			int ninv=ksm(n,mod-2);
			for(int i=0;i<n;i++) f[i]=f[i]*ninv%mod;
		}
	}
	void MUL(ll *s,ll *f,ll *h,int n,int m)
	{
		int lim=pre(n,m);
		for(int i=0;i<=n;i++) A[i]=f[i];
		for(int i=0;i<=m;i++) B[i]=h[i];
		for(int i=n+1;i<=(1<<lim);i++) A[i]=0;
		for(int i=m+1;i<=(1<<lim);i++) B[i]=0;
		NTT(A,(1<<lim),1);NTT(B,(1<<lim),1);
		for(int i=0;i<=(1<<lim)-1;i++) s[i]=A[i]*B[i]%mod;
		NTT(s,(1<<lim),-1);
	}
	void INV(ll *s,ll *f,int n)
	{
		S[0]=ksm(f[0],mod-2);S[1]=0;
		for(int len=2;len<=(n<<1);len<<=1)
		{
			ll lim=(len<<1);
			for(int i=0;i<len;i++) A[i]=f[i],B[i]=S[i];
			for(int i=len;i<lim;i++) A[i]=B[i]=0;
			pre(len,0);
			NTT(A,lim,1); NTT(B,lim,1);
			for(int j=0;j<lim;j++)
				S[j]=(2*B[j]%mod+mod-A[j]*B[j]%mod*B[j]%mod)%mod;
			NTT(S,lim,-1);
			for(int j=len;j<lim;j++) S[j]=0;
		}
		for(int i=0;i<=n;i++) s[i]=S[i];
	}
	void ADD(ll *s,ll *f,ll *h,int n,int m)
	{
		for(int i=0;i<=max(n,m);i++) s[i]=(f[i]+h[i])%mod;
	}
	void DEL(ll *s,ll *f,ll *h,int n,int m)
	{
		for(int i=0;i<=max(n,m);i++) s[i]=(f[i]-h[i]+mod)%mod;
	}
	void REV(ll *f,int n)
	{
		for(int i=0;i<=n/2;i++) swap(f[i],f[n-i]);
	}
	void DIV(ll *q,ll *r,ll *f,ll *h,int n,int m)
	{
		static ll A[maxn],B[maxn],C[maxn],D[maxn];
		for(int i=0;i<=n;i++) A[i]=C[i]=f[i];
		for(int i=0;i<=m;i++) B[i]=D[i]=h[i];
		REV(A,n); 
		REV(B,m); 
		INV(B,B,n-m); 
		MUL(q,A,B,n,n-m);
		for(int i=n-m+1;i<=n+n-m;i++) q[i]=0;
		REV(q,n-m);
		MUL(D,D,q,m,n-m);
		DEL(r,C,D,n,n);
	}
	void SQRT(ll *s,ll *f,int n)
	{
		static ll S[maxn],A[maxn],B[maxn],C[maxn];
		S[0]=1;
		for(int len=1;len<=(n<<1ll);len<<=1)
		{
			ll lim=len<<1;
			for(int i=0;i<len;i++) A[i]=f[i],B[i]=S[i];
			for(int i=len;i<lim;i++) A[i]=B[i]=C[i]=0;
			INV(C,B,len);
			pre(len,0); NTT(A,lim,1); NTT(C,lim,1);
			for(int j=0;j<lim;j++) S[j]=A[j]*C[j]%mod;
			NTT(S,lim,-1);
			ADD(S,S,B,lim,lim);
			ll inv2=ksm(2,mod-2);
			for(int i=0;i<lim;i++) S[i]=S[i]*inv2%mod;
			for(int i=len;i<lim;i++) S[i]=0;

		}
		for(int i=0;i<=n;i++) s[i]=S[i];
	}	
	void MUL_integer(ll *s,ll *f,int n,ll k)
	{
		for(int i=0;i<=n;i++) S[i]=f[i]*k%mod;
		for(int i=0;i<=n;i++) s[i]=S[i];
	}
	void DERIV(ll *s,ll *f,int n)
	{
		static ll A[maxn];A[n]=0;
		for(int i=1;i<=n;i++) A[i-1]=f[i]*i%mod;
		for(int i=0;i<=n;i++) s[i]=A[i];
	}
	void LIMIT(ll *s,ll *f,int n)
	{
		A[0]=0;
		for(int i=0;i<n;i++) A[i+1]=f[i]*ksm(i+1,mod-2)%mod;
		for(int i=0;i<=n;i++) s[i]=A[i];
	}
	void Ln(ll *s,ll *f,int n)
	{
		static ll A[maxn],B[maxn];
		int lim=pre(n,n);
		for(int i=0;i<=n;i++) A[i]=f[i],B[i]=0;
		for(int i=n+1;i<=(1<<lim);i++) A[i]=B[i]=0;
		DERIV(B,A,n); 
		INV(A,A,n); 
		MUL(A,A,B,n,n);
		LIMIT(A,A,n);
		for(int i=0;i<=n;i++) s[i]=A[i];
	}
	void EXP(ll *s,ll *f,int n)
	{
		static ll A[maxn],B[maxn],C[maxn],S[maxn];
		S[0]=1; S[1]=0;
		for(ll len=2;len<=(n<<1);len<<=1)
		{
			int lim=len<<1;
			for(int i=0;i<len;i++) A[i]=f[i],B[i]=S[i];
			for(int i=len;i<lim;i++) A[i]=B[i]=C[i]=0;
			Ln(C,B,len-1);
			for(int i=0;i<len;i++) C[i]=(A[i]-C[i]+mod)%mod;
			C[0]=(C[0]+1)%mod;
			pre(len,0); NTT(B,lim,1); NTT(C,lim,1);
			for(int j=0;j<lim;j++) S[j]=B[j]*C[j]%mod;
			NTT(S,lim,-1);
			for(int j=len;j<lim;j++ )S[j]=0;
 		}
 		for(int i=0;i<=n;i++) s[i]=S[i];
	}	
	void POW(ll *s,ll *f,int n,ll k)
	{
		int lim=pre(n,n);
		for(int i=0;i<=n;i++) A[i]=f[i];
		for(int i=n+1;i<=(1<<lim);i++) A[i]=0;
		Ln(A,A,n); MUL_integer(A,A,n,k);
		EXP(A,A,n);
		for(int i=0;i<=n;i++) s[i]=A[i];
	}
	const int img=86583718;
	void sin(ll *s,ll *f,int n)
	{
		static ll S[maxn],H[maxn];
		for(int i=0;i<=n;i++) S[i]=f[i]*img%mod;
		EXP(S,S,n); INV(H,S,n);
		ll t=ksm(2*img%mod,mod-2);
		for(int i=0;i<=n;i++)
			s[i]=(S[i]-H[i]+mod)%mod*t%mod;
	}
	void cos(ll *s,ll *f,int n)
	{
		static ll S[maxn],H[maxn];
		for(int i=0;i<=n;i++) S[i]=f[i]*img%mod;
		EXP(S,S,n); INV(H,S,n);
		ll t=ksm(2,mod-2);
		for(int i=0;i<=n;i++)
			s[i]=(S[i]+H[i])%mod*t%mod;	
	}
	void ARCSIN(ll *s,ll *f,int n)
	{
		static ll A[maxn],B[maxn];
		for(int i=0;i<=n;i++) A[i]=B[i]=f[i];
		DERIV(B,B,n); MUL(A,A,A,n,n);
		for(int i=0;i<=n;i++) A[i]=(mod-A[i])%mod;
		A[0]=(A[0]+1)%mod;
		SQRT(A,A,n);
		INV(A,A,n);
		MUL(A,A,B,n,n);
		LIMIT(A,A,n);
		for(int i=0;i<=n;i++) s[i]=A[i];
	}
	void ARCTAN(ll *s,ll *f,int n)
	{
		static ll A[maxn],B[maxn];
		for(int i=0;i<=n;i++) A[i]=B[i]=f[i];
		DERIV(B,B,n); MUL(A,A,A,n,n);
		A[0]=(A[0]+1)%mod;
		INV(A,A,n);
		MUL(A,A,B,n,n);
		LIMIT(A,A,n);
		for(int i=0;i<=n;i++) s[i]=A[i];
	}
}

留个坑(((

本文作者:cc0000

本文链接:https://www.cnblogs.com/cc0000/p/17009204.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   cc0000  阅读(42)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起