【学习笔记】多项式 3:多项式运算
1.【学习笔记】Kruskal 重构树2.【学习笔记】网络流3.【学习笔记】高级数据结构4.【学习笔记】线性基5.【学习笔记】Link Cut Tree6.【学习笔记】字符串后缀算法7.【学习笔记】字符串回文算法8.【学习笔记】组合数学9.【学习笔记】多项式 1:基础操作10.【学习笔记】多项式 2:集合幂级数
11.【学习笔记】多项式 3:多项式运算
12.【学习笔记】Prufer 序列13.【学习笔记】多项式 4:生成函数14.【学习笔记】DP 套 DP15.【学习笔记】图的连通性16.【学习笔记】差分约束17.【学习笔记】长链剖分18.【学习笔记】2-SAT19.【学习笔记】根号算法20.【学习笔记】Primal-Dual 原始对偶算法21.【学习笔记】Bostan-Mori 算法22.【学习笔记】狄利克雷卷积与高级筛法23.【学习笔记】DP 优化 1:基础优化24.【学习笔记】DP 优化 2:动态 DP25.【学习笔记】李超线段树26.【学习笔记】优化建图27.【学习笔记】Segment Tree Beats28.【学习笔记】插头 DP29.【学习笔记】任意模数多项式乘法30.【学习笔记】SG 函数与 SG 定理31.【学习笔记】类欧几里得算法32.【学习笔记】狄利克雷前/后缀和/差分33.【学习笔记】DSU on Tree34.【学习笔记】DP 优化 3:闵可夫斯基和优化 DP35.【学习笔记】笛卡尔树36.【学习笔记】Miller-Rabin 算法37.【学习笔记】DP 优化 4:决策单调性38.【学习笔记】DP 优化 5:wqs 二分优化 DP39.【学习笔记】边分治40.【学习笔记】KMP 相关算法41.【学习笔记】概率生成函数42.【学习笔记】离散对数和剩余多项式求导与积分#
单独对每一项操作后加和。
预处理逆元,时间复杂度 。
inline Poly Differntial(int n){
Poly F;
F.set(n);
for(int i=1;i<n;++i) F[i-1]=f[i]*i%mod;
return F;
}
inline Poly Integral(int n){
Poly F;
F.set(n+1);
for(int i=0;i<n;++i) F[i+1]=f[i]*inv[i+1]%mod;
return F;
}
多项式牛顿迭代#
牛顿强啊!
设函数 ,要求一多项式 ,满足:
假定已经求得 ,满足:
泰勒展开:
由于右侧 的最低非零次项次数为 ,因此:
于是式子实际上是:
整理一下就是:
于是我们只需要求出 再倍增即可。
多项式求逆#
给定 ,求 使得:
常规倍增法#
假设已经求得 满足:
接下来推一下式子:
于是得到:
牛顿迭代法#
构造:
代入牛顿迭代式:
整理一下就是:
inline Poly Inv(int n){
Poly F,G;
G.set(1);
G[0]=q_pow(f[0],mod-2,mod);
for(int L=2;L<2*n;L<<=1){
F.set(2*L),G.set(2*L);
F.clear(0,2*L-1);
for(int i=0;i<L;++i) F[i]=f[i];
F.NTT(2*L,1),G.NTT(2*L,1);
for(int i=0;i<2*L;++i) G[i]=1ll*(int)G[i]*(2ll-1ll*(int)G[i]*(int)F[i]%mod+mod)%mod;
G.NTT(2*L,0);
G.clear(min(n,L),2*L-1);
}
return G;
}
多项式开根#
给定 ,求 使得:
常规倍增法#
假设已经求得 满足:
接下来推一下式子:
于是得到:
即:
牛顿迭代法#
构造:
代入牛顿迭代式:
整理一下就是:
即:
inline Poly Sqrt(int n){
Poly F,G,invG,H;
G.set(1);
G[0]=1;
for(int L=2;L<2*n;L<<=1){
F.set(2*L),G.set(2*L),H.set(2*L);
F.clear(0,2*L-1);
for(int i=0;i<L;++i) F[i]=f[i];
invG=G.Inv(L);
F.NTT(2*L,1),invG.NTT(2*L,1);
for(int i=0;i<2*L;++i) H[i]=F[i]*invG[i]%mod*inv[2]%mod;
H.NTT(2*L,0);
for(int i=0;i<2*L;++i) G[i]=(H[i]+G[i]*inv[2]%mod)%mod;
G.clear(min(n,L),2*L-1);
}
return G;
}
多项式对数函数#
给定 ,求 使得:
左侧相当于一个复合函数,对左右求导:
根据简单初等函数的导数得:
求出 后积分得到 :
inline Poly Ln(int n){
Poly dF,invF,G,H;
dF=Differntial(n),invF=Inv(n);
int L=1;
while(L<2*n) L<<=1;
dF.set(L),invF.set(L),G.set(L);
dF.NTT(L,1),invF.NTT(L,1);
for(int i=0;i<L;++i) G[i]=dF[i]*invF[i]%mod;
G.NTT(L,0);
H=G.Integral(L);
H.clear(n,L);
return H;
}
注意多项式牛顿迭代和多项式 在求导时的区别,前者的 是关于 的函数,也即 ;后者 是关于 的函数,也即 ,而左侧的 是关于 的复合函数,所以要应用复合函数求导 。
多项式指数函数#
给定 ,求 使得:
使用牛顿迭代法,构造:
代入牛顿迭代式:
整理一下就是:
inline Poly Exp(int n){
Poly F,G,lnG;
G.set(1);
G[0]=1;
for(int L=2;L<2*n;L<<=1){
F.set(2*L),G.set(2*L);
F.clear(0,2*L-1);
for(int i=0;i<L;++i) F[i]=f[i];
lnG=G.Ln(L);
F.NTT(2*L,1),G.NTT(2*L,1),lnG.NTT(2*L,1);
for(int i=0;i<2*L;++i) G[i]=G[i]*(1ull-lnG[i]+F[i]+mod)%mod;
G.NTT(2*L,0);
G.clear(min(n,L),2*L-1);
}
return G;
}
多项式半家桶封装模板#
点击查看代码
inline int q_pow(int A,int B,int P){
int res=1;
while(B){
if(B&1) res=1ll*res*A%P;
A=1ll*A*A%P;
B>>=1;
}
return res;
}
int inv[maxn];
int rev[maxn];
int base,w[maxn];
struct Poly{
const static int g=3;
int deg;
vector<ull> f;
ull &operator[](const int &i){return f[i];}
ull operator[](const int &i)const{return f[i];}
inline void set(int L){deg=L;f.resize(L);}
inline void clear(int L,int R){for(int i=L;i<=R;++i)f[i]=0;}
inline void output(int L){for(int i=0;i<L;++i)printf("%llu ",f[i]);printf("\n");}
inline void NTT(int L,bool type){
set(L);
for(int i=1;i<L;++i){
rev[i]=(rev[i>>1]>>1)+(i&1?L>>1:0);
if(i<rev[i]) swap(f[i],f[rev[i]]);
}
for(int d=1;d<L;d<<=1){
base=q_pow(type?g:q_pow(g,mod-2,mod),(mod-1)/(2*d),mod);
w[0]=1;
for(int i=1;i<d;++i) w[i]=1ll*w[i-1]*base%mod;
for(int i=0;i<L;i+=d<<1){
for(int j=0;j<d;++j){
ull x=f[i+j],y=f[i+d+j]*w[j]%mod;
f[i+j]=x+y,f[i+d+j]=x-y+mod;
}
}
}
for(int i=0;i<L;++i) f[i]%=mod;
if(!type){
int inv_L=q_pow(L,mod-2,mod);
for(int i=0;i<L;++i) f[i]=f[i]*inv_L%mod;
}
}
inline Poly Differntial(int n){
Poly F;
F.set(n);
for(int i=1;i<n;++i) F[i-1]=f[i]*i%mod;
return F;
}
inline Poly Integral(int n){
Poly F;
F.set(n+1);
for(int i=0;i<n;++i) F[i+1]=f[i]*inv[i+1]%mod;
return F;
}
inline Poly Inv(int n){
Poly F,G;
G.set(1);
G[0]=q_pow(f[0],mod-2,mod);
for(int L=2;L<2*n;L<<=1){
F.set(2*L),G.set(2*L);
F.clear(0,2*L-1);
for(int i=0;i<L;++i) F[i]=f[i];
F.NTT(2*L,1),G.NTT(2*L,1);
for(int i=0;i<2*L;++i) G[i]=1ll*(int)G[i]*(2ll-1ll*(int)G[i]*(int)F[i]%mod+mod)%mod;
G.NTT(2*L,0);
G.clear(min(n,L),2*L-1);
}
return G;
}
inline Poly Sqrt(int n){
Poly F,G,invG,H;
G.set(1);
G[0]=1;
for(int L=2;L<2*n;L<<=1){
F.set(2*L),G.set(2*L),H.set(2*L);
F.clear(0,2*L-1);
for(int i=0;i<L;++i) F[i]=f[i];
invG=G.Inv(L);
F.NTT(2*L,1),invG.NTT(2*L,1);
for(int i=0;i<2*L;++i) H[i]=F[i]*invG[i]%mod*inv[2]%mod;
H.NTT(2*L,0);
for(int i=0;i<2*L;++i) G[i]=(H[i]+G[i]*inv[2]%mod)%mod;
G.clear(min(n,L),2*L-1);
}
return G;
}
inline Poly Ln(int n){
Poly dF,invF,G,H;
dF=Differntial(n),invF=Inv(n);
int L=1;
while(L<2*n) L<<=1;
dF.set(L),invF.set(L),G.set(L);
dF.NTT(L,1),invF.NTT(L,1);
for(int i=0;i<L;++i) G[i]=dF[i]*invF[i]%mod;
G.NTT(L,0);
H=G.Integral(L);
H.clear(n,L);
return H;
}
inline Poly Exp(int n){
Poly F,G,lnG;
G.set(1);
G[0]=1;
for(int L=2;L<2*n;L<<=1){
F.set(2*L),G.set(2*L);
F.clear(0,2*L-1);
for(int i=0;i<L;++i) F[i]=f[i];
lnG=G.Ln(L);
F.NTT(2*L,1),G.NTT(2*L,1),lnG.NTT(2*L,1);
for(int i=0;i<2*L;++i) G[i]=G[i]*(1ull-lnG[i]+F[i]+mod)%mod;
G.NTT(2*L,0);
G.clear(min(n,L),2*L-1);
}
return G;
}
};
参考资料#
- OI Wiki
作者:SoyTony
出处:https://www.cnblogs.com/SoyTony/p/Learning_Notes_about_Polynomial_3.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
合集:
学习笔记
分类:
数学/多项式/多项式运算
, A/学习笔记
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效