多 项 式 全 家 桶(便携式)
多项式卷积
用 表示 与 的卷积。暂时略去 FFT 与 NTT 的推导过程(应该……会补的吧?)。时间复杂度 。
多项式牛顿迭代
给定 。求 使 。这里 。
考虑倍增。 时单独求解。假设已经得到了 的解 ,考虑 。
将 在 处进行泰勒展开,有
因为 的最低非零项次数为 ,所以 时的项恒为 。因此
一般来说不会直接用到,但是可以用它直接解决下面的几个问题。
多项式乘法逆
给定 ,求 使 。 可以记作 或 。
应用牛顿迭代。方程是 。有 。时间复杂度 。
多项式带余除法
给定 ,求 满足 。可以证明 是唯一存在的。
记 表示将 的系数序列翻转之后的多项式, 同理。记 。考虑将 作为自变量代入式子,则得到 。式子两边对 取模得到 。而 ,所以直接用多项式乘法计算 就可以得到 。有了 自然有 ,那么 即可。时间复杂度 。
多项式开方
给定 ,求 使 。
应用牛顿迭代。有 。时间复杂度 。
多项式求导 / 不定积分
太简单了。直接按照定义做就可以了。时间复杂度 。
多项式 ln
给定 ,求 使 。注意只有当 时有解。
没法处理,考虑两边求导。有 。于是 。
多项式 exp
给定 ,求 使 。注意只有当 时有解。
应用牛顿迭代。有 。时间复杂度 。
多项式快速幂
给定 ,求 。
快速幂使用倍增?大可不必。直接做 即可。如果 则只要用 计算,最后乘上 。时间复杂度 。注意可能需要特判 的情形。
其实直接使用倍增当然也是可以的,还能够处理任意的模多项式。
const int N=2e5+5,P=998244353; int qpow(int a,int b=P-2){ int c=1; for(;b;b>>=1,a=1ll*a*a%P) if(b&1)c=1ll*c*a%P; return c; } typedef vector<int> arr; namespace poly{ const int _G=3,invG=::qpow(3); int tr[N<<1]; void NTT(arr&f,int op){ int n=f.size(); for(int i=0;i<n;++i) if(i<tr[i])swap(f[i],f[tr[i]]); for(int p=2;p<=n;p<<=1){ int len=p>>1,tG=::qpow(op==1?_G:invG,(P-1)/p); for(int k=0;k<n;k+=p){ int buf=1; for(int l=k;l<k+len;++l){ int tmp=1ll*buf*f[len+l]%P; f[len+l]=(f[l]-tmp+P)%P;f[l]=(f[l]+tmp)%P; buf=1ll*buf*tG%P; } } } if(op==-1){ int inv=::qpow(n); for(int i=0;i<n;++i)f[i]=1ll*f[i]*inv%P; } }//NTT模板 arr times(arr f,arr g){ int n=f.size(),m=g.size(); for(m+=n,n=1;n<=m;n<<=1); f.resize(n);g.resize(n); for(int i=0;i<n;++i) tr[i]=(tr[i>>1]>>1)|((i&1)?n>>1:0); NTT(f,1);NTT(g,1); for(int i=0;i<n;++i)f[i]=1ll*f[i]*g[i]%P; NTT(f,-1);return f; }//多项式卷积 arr inv(int n,arr f){ if(n==1)return {::qpow(f[0])}; arr g=inv((n+1)/2,f);f.resize(n); f=times(f,g);for(int i=0;i<n;i++)f[i]=P-f[i];f[0]+=2; f.resize(n);f=times(f,g);f.resize(n);return f; }//多项式求逆 arr sqrt(int n,arr f){ if(n==1)return {1};//这里只考虑f[0]=1的情况。实际上可能要求二次剩余。 arr g1=sqrt((n+1)/2,f);f.resize(n); arr g=times(g1,g1);g.resize(n);int inv2=(P+1)/2; for(int i=0;i<n;i++)g[i]=1ll*(f[i]+g[i])%P*inv2%P; g1.resize(n);g1=inv(n,g1);g=times(g,g1);g.resize(n); return g; }//多项式开根 pair<arr,arr> mod(arr f,arr g){ int n=f.size(),m=g.size();arr ff=f,gg=g; reverse(ff.begin(),ff.end()); reverse(gg.begin(),gg.end());gg.resize(n+1); arr q=times(ff,inv(n+1,gg)); q.resize(n-m+1);reverse(q.begin(),q.end()); arr r=times(g,q);r.resize(m-1); for(int i=0;i<m-1;i++)r[i]=(f[i]-r[i]+P)%P; return make_pair(q,r); }//多项式带余除法 arr ln(arr f){ int n=f.size();arr f1;f1.resize(n); for(int i=1;i<n;i++)f1[i-1]=1ll*f[i]*i%P; f=inv(n,f);f1=times(f1,f);f1.resize(n); f[0]=0;for(int i=1;i<n;i++)f[i]=1ll*f1[i-1]*::qpow(i)%P; return f; }//多项式 ln arr exp(int n,arr f){ if(n==1)return {1}; arr g1=exp((n+1)/2,f);f.resize(n);g1.resize(n); arr g=ln(g1);for(int i=0;i<n;i++)g[i]=(f[i]-g[i]+P)%P;++g[0]; g=times(g,g1);g.resize(n);return g; }//多项式 exp arr qpow(arr f,int k1,int k2){ //因为k可能很大,所以传入k1=k%P,k2=k%(P-1) int n=f.size(),x=f[0],invx=::qpow(x); for(int i=0;i<n;i++)f[i]=1ll*f[i]*invx%P; f=ln(f);for(int i=0;i<n;i++)f[i]=1ll*f[i]*k1%P; f=exp(n,f);x=::qpow(x,k2); for(int i=0;i<n;i++)f[i]=1ll*f[i]*x%P; return f; }//多项式快速幂 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具