[学习笔记]多项式指数函数
https://blog.csdn.net/semiwaker/article/details/73251486
已知$B(x)$求:$A(x)=e^{B(x)}$
根据麦克劳林展开:$e^{B(x)}=1+\frac{B(x)}{1!}+\frac{{B(x)}^2}{2!}+...+\frac{{B(x)}^n}{n!}$
用到指数函数的时候,就是推出式子是麦克劳林展开的时候luoguP4841 城市规划
前置知识:
1.牛顿迭代
至于g(f(x))没有什么具体表达式当然也是没有办法算的。
关于泰勒展开泰勒公式_百度百科
思路就是用某一个点的n阶导数和本身的函数值,来无限逼近整个函数的值
后面的麦克劳林展开用的也比较多
第一点非常关键,
就是,我们这里要求F(x),所以不妨把F(x)看做变量x,这样,A(x)就是常数,
反正,式子就是:g(f)=f^2-A,直接求导即可
(至于多项式对数函数的求导,那个是把x看做自变量(G(x)是一次的,再看成自变量就没了。。))
2.多项式对数函数
正题
代码:
注意lnG(X)这里,必须是mod x^n的意义下的
#include<bits/stdc++.h> #define il inline #define reg register int #define numb (ch^'0') using namespace std; typedef long long ll; il void rd(int &x){ char ch;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } namespace Miracle{ const int N=8*1e5+5; const int mod=998244353; const int G=3; const int GI=332748118; int n,m; int qm(int x,int y){ int ret=1; while(y){ if(y&1) ret=(ll)ret*x%mod; x=(ll)x*x%mod; y>>=1; } return ret; } int f[N],t[N],e[N],b[N],p[N],ni[N],g[N],lg[N]; int rev[N]; void NTT(int *f,int n,int c){ for(reg i=0;i<n;++i){ if(i<rev[i]) swap(f[i],f[rev[i]]); } for(reg p=2;p<=n;p<<=1){ int gen; if(c==1) gen=qm(G,(mod-1)/p); else gen=qm(GI,(mod-1)/p); for(reg l=0;l<n;l+=p){ int buf=1; for(reg k=l;k<l+p/2;++k){ int tmp=(ll)buf*f[k+p/2]%mod; f[k+p/2]=(f[k]-tmp+mod)%mod; f[k]=(f[k]+tmp)%mod; buf=(ll)buf*gen%mod; } } } } void inv(int *f,int *g,int n){ if(n==1){ g[0]=qm(f[0],mod-2);return; } inv(f,g,n>>1); for(reg i=0;i<n;++i) p[i]=f[i]; for(reg i=n;i<2*n;++i) p[i]=0; for(reg i=0;i<2*n;++i){ rev[i]=rev[i>>1]>>1|((i&1)?n:0); } NTT(g,2*n,1);NTT(p,2*n,1); for(reg i=0;i<2*n;++i){ g[i]=((ll)2-(ll)g[i]*p[i]%mod+mod)%mod*g[i]%mod; } NTT(g,2*n,-1); int iv=qm(2*n,mod-2); for(reg i=0;i<2*n;++i){ if(i<n) g[i]=(ll)g[i]*iv%mod; else g[i]=0; } } void dao(int *f,int n){ for(reg i=0;i<n-1;++i){ f[i]=(ll)f[i+1]*(i+1)%mod; } f[n-1]=0; } void ji(int *f,int n){ for(reg i=n-1;i>=1;--i){ f[i]=(ll)f[i-1]*qm(i,mod-2)%mod; } f[0]=0; } void ln(int *f,int *g,int n){ for(reg i=0;i<n;++i) ni[i]=0; for(reg i=n;i<2*n;++i) ni[i]=0,b[i]=0; inv(f,ni,n); for(reg i=0;i<n;++i) b[i]=f[i]; dao(b,n); for(reg i=0;i<2*n;++i){ rev[i]=rev[i>>1]>>1|((i&1)?n:0); } NTT(b,2*n,1);NTT(ni,2*n,1); for(reg i=0;i<2*n;++i){ g[i]=(ll)b[i]*ni[i]%mod; } NTT(g,2*n,-1); int iv=qm(2*n,mod-2); for(reg i=0;i<2*n;++i){ if(i<n) g[i]=(ll)g[i]*iv%mod; else g[i]=0; } ji(g,n); } void exp(int *f,int *g,int n){ if(n==1){ g[0]=1;return; } exp(f,g,n>>1); for(reg i=0;i<n;++i) lg[i]=0; ln(g,lg,n); // cout<<" Exp "<<n<<endl; // for(reg i=0;i<n;++i){ // printf("%d ",lg[i]); // }puts(""); // cout<<" now "<<endl; // for(reg i=0;i<n;++i){ // cout<<g[i]<<" "; // }cout<<endl; lg[0]=(1+f[0]-lg[0]+mod)%mod; for(reg i=1;i<n;++i) lg[i]=(f[i]-lg[i]+mod)%mod; // cout<<" glglg "<<endl; // for(reg i=0;i<n;++i){ // cout<<lg[i]<<" "; // }cout<<endl; // for(reg i=0;i<n;++i) p[i]=f[i]; // for(reg i=n;i<2*n;++i) p[i]=0; // NTT(p,2*n,1); for(reg i=0;i<2*n;++i){ rev[i]=rev[i>>1]>>1|((i&1)?n:0); } NTT(lg,2*n,1);NTT(g,2*n,1); // for(reg i=0;i<2*n;++i){ // g[i]=(ll)(1-lg[i]+p[i]+mod)%mod*g[i]%mod; // } for(reg i=0;i<2*n;++i){ g[i]=(ll)lg[i]*g[i]%mod; } NTT(g,2*n,-1); int iv=qm(2*n,mod-2); for(reg i=0;i<2*n;++i){ if(i<n) g[i]=(ll)g[i]*iv%mod; else g[i]=0; } } int main(){ rd(n); for(reg i=0;i<n;++i) rd(f[i]); int len,lp; for(lp=n,len=1;len<=lp;len<<=1); // cout<<" start len "<<len<<endl; exp(f,g,len); for(reg i=0;i<n;++i){ printf("%d ",g[i]); } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/2/1 16:01:41 */