多项式求ln,exp

2019-04-14 11:55发布

class="markdown_views prism-atom-one-light">

迭代法求零点

已知ff是一个多项式对多项式的函数,现要逼近f的零点,采用倍增法: 假如要求A模xnx^n意义下的值,则预先求出A0为A模xn/2x^{n/2}意义下的值
由泰勒展开,f(A)=f(A0)+f(A0)(AA0)f(A)=f(A0)+f'(A0)(A-A0)在模xnx^n意义下成立。令f(A)=0f(A)=0,化简后:
A=A0f(A0)f(A0)A=A0-frac {f(A0)} {f'(A0)}
(牛顿迭代的式子)
由此式可求出A在模xnx^n意义下的值。

推求逆

求D的逆,令f(x)=1xDf(x)=frac 1 x - D即可

推开方

f(x)=x2Df(x)=x^2-D即可

推exp

f(x)=lnxDf(x)=ln x-D即可。
注意此时,由于上式泰勒展开是对多项式x进行的,因此lnxln x的导数直接就是1/x1/x

推ln

这个和迭代没啥关系
先求其导函数,再求其积分
注意此时是对数x求导,而不是多项式,所以是复合函数求导。 lnF(x)=F(x)F(x)ln' F(x)=frac {F'(x)} {F(x)}
计算出上式后积分即可。
求ln时要保证给定多项式常数项为1,最后结果常数项默认为0。

积分、求导

O(n)计算即可。积分的常数项视作0. 板子 #include #include #include #include using namespace std; typedef long long ll; const int mo=998244353,N=1e6+10000; int cnt[N],n,m,Mx,mx; ll g[N],w[N],iw[N],jc[N],njc[N],ans[N],inv[N]; ll ksm(ll x,ll y){ ll ret=1;for(;y;y>>=1){ if(y&1)ret=ret*x%mo; x=x*x%mo; } return ret; } int h[N]; void dft(ll *a,int sz,int sig){ for(int i=0;i<sz;i++){ h[i]=(h[i>>1]>>1)+(sz>>1)*(i&1); if(h[i]<i)swap(a[i],a[h[i]]); } for(int m=2;m<=sz;m<<=1){ int hf=m>>1,step=Mx/m; for(int i=0;i<sz;i+=m){ for(int j=0;j<hf;j++){ ll T=a[i+j+hf]*(sig==1?w[j*step]:iw[j*step])%mo; a[i+j+hf]=(a[i+j]-T)%mo; a[i+j]=(a[i+j]+T)%mo; } } } if(sig==-1){ ll ny=ksm(sz,mo-2); for(int i=0;i<sz;i++)a[i]=a[i]*ny%mo; } } ll ZZ[N],TT[N]; void getinv(ll *T,ll *Z,int sz){ memset(T,0,sz*8*2); memset(TT,0,sz*8*2); memset(ZZ,0,sz*8*2); T[0]=ksm(Z[0],mo-2); for(int r=2;r<=sz;r<<=1){ memcpy(TT,T,r*8); dft(TT,2*r,1); memcpy(ZZ,Z,r*8); dft(ZZ,2*r,1); for(int i=0;i<2*r;i++)T[i]=TT[i]*(2-ZZ[i]*TT[i]%mo)%mo; dft(T,2*r,-1); for(int i=r;i<2*r;i++)T[i]=0; } } void qiudao(ll *a,int sz){ for(int i=0;i<sz;i++) a[i]=a[i+1]*(i+1)%mo; } void jifen(ll *a,int sz){ for(int i=sz-1;i;i--)a[i]=a[i-1]*inv[i]%mo; a[0]=0; } ll OO[N]; void getln(ll *U,ll *O,int sz){ memset(U,0,sz*8*2); memcpy(U,O,sz*8); qiudao(U,sz); getinv(OO,O,sz); dft(U,sz*2,1); dft(OO,sz*2,1); for(int i=0;i<sz*2;i++)U[i]=U[i]*OO[i]%mo; dft(U,sz*2,-1); for(int i=sz;i<2*sz;i++)U[i]=0; jifen(U,sz); } ll lnd[N],DD[N],SS[N]; void getexp(ll *D,ll *S,int sz){ memset(D,0,sz*8*2); memset(DD,0,sz*8*2); memset(SS,0,sz*8*2); memset(lnd,0,sz*8*2); D[0]=1; for(int r=2;r<=sz;r<<=1){ getln(lnd,D,r); for(int i=0;i<r;i++)lnd[i]=(-lnd[i]+S[i])%mo; lnd[0]++; dft(lnd,2*r,1); memcpy(DD,D,8*r); dft(DD,2*r,1); for(int i=0;i<2*r;i++) D[i]=DD[i]*lnd[i]%mo; dft(D,2*r,-1); for(int i=r;i<2*r;i++)D[i]=0; } } ll TE[N]; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); cin>>n>>m; for(int i=1;i<=n;i++){ int x;scanf("%d",&x);cnt[x]++; } for(int i=1;i<=m;i++)if(cnt[i]){ for(int j=i;j<=m;j+=i){ g[j-1]=(g[j-1]+i*cnt[i])%mo; } } for(Mx=1;Mx<=m*2;Mx<<=1); w[0]=iw[0]=1;w[1]=ksm(3,(mo-1)/Mx); iw[1]=ksm(w[1],mo-2); for(int i=2;i<Mx;i++){ w[i]=w[i-1]*w[1]%mo,iw[i]=iw[i-1]*iw[1]%mo; } jc[0]=1;for(int i=1;i<=m;i++)jc[i]=jc[i-1]*i%mo; njc[m]=ksm(jc[m],mo-2); for(int i=m-1;~i;i--)njc[i]=njc[i+1]*(i+1)%mo; for(int i=1;i<=m;i++)inv[i]=njc[i]*jc[i-1]%mo; jifen(g,m+1); getexp(ans,g,Mx>>1); for(int i=1;i<=m;i++)printf("%lld ",(ans[i]+