形如 f(x)=a0x0+a1x1+a2x2+⋯+an−1xn−1。
点值表示法:通过代入 n 个不同的值 x0,x1…xn−1 到 f(x) 中,得到 y0,y1...yn−1,用 (x0,y0),(x1,y1)…(xn−1,yn−1) 即可表示这个多项式。
若用点值表示法,并且两个多项式的 x 对应相等,那么将 y 对应相乘,即可 O(n) 的得到它们乘积的点值表示法。
从多项式的系数表示向点值表示的转化,称为求值,从多项式的点值表示向系数表示的转化,称为插值。
快速傅里叶变换可以做到 O(nlogn) 进行求值和插值。
复数相乘,模长相乘,幅角相加。
(a+bi)×(c+di)=(ac−bd)+(bc+ad)i
在复平面上,以原点为圆心,1 为半径作圆,所得的圆叫单位圆。以圆点为起点,圆的 n 等分点为终点,做 n 个向量,设幅角为正且最小的向量对应的复数为 ωn,称为 n 次单位根。
ωkn=cos2πkn+isin2πknω2k2n=ωknωk+n2n=−ωkn
f(x)=a0x0+a1x1+a2x2+a3x3+⋯+an−2xn−2+an−1xn−1
进行奇偶分类得:
f1(x)=a0+a2x1+a4x2+a6x3+⋯+an−2xn2−1f2(x)=a1+a3x1+a5x2+a7x3+⋯+an−1xn2−1
得 f(x)=f1(x2)+xf2(x2)。
设 k<n2,代入 ωkn 得:
f(ωkn)=f1(ω2kn)+ωknf2(ω2kn)
再代入 ωk+n2n 得
f(ωk+n2n)=f1(ω2kn)−ωknf2(ω2kn)
通过这两个式子,我们就可以进行递归求解了,但因递归常数过大,我们通过迭代来实现。
我们将原多项式系数重新排序,将每个系数都在它递归的最后位置,就可以用迭代来代替递归实现。
发现原来在第 a 个位置的系数,在递归的最后位置为 a 的二进制反转以后的数。

这称为蝴蝶操作。
代入 ω−kn,可再次求得一系列值,将其除以 n 即可求得多项式相乘后的系数表示。
若 a,p 互素,且 p>1,对于 an≡1(modm) 最小的 n,称为 a 模 p 的阶,记作 δp(a)。
设 p 是正整数,a 是整数,若 δp(a)=φ(p),则称 a 为模 p 的一个原根。
原根个数不唯一。
若 P 为素数,设 G 为 P 的原根,那么 GimodP,(i<G<P,0<i<P) 的结果两两不同。
模数有 998244353,1004535809,469762049,原根都为 3。
ωn≡gp−1n(modp)
[xi]f′(x)=(i+1)[xi+1]f(x)[xi]∫f(x)=1i[xi−1]f(x)
已知 f(x),求 g(x),满足 f(g(x))≡0(modxn)。
设已经求得 g0(x),满足 g0(x)≡g(x)(modxn),由泰勒展开得:
0=f(g(x))=f(g0(x))+f′(g0(x))(g(x)−g0(x))+f′′(g0(x))2(g(x)−g0(x))2+…≡f(g0(x))+f′(g0(x))(g(x)−g0(x))(modx2n)
得:
g(x)≡g0(x)−f(g0(x))f′(g0(x))(modx2n)
f(x)g(x)≡1(modxn)
称 g(x) 为 f(x) 的逆元,模 xn 的意义是将次数大于等于 n 的项都忽略掉。
设已经求得满足
f(x)g(x)≡1(modxn)
的 g(x),得:
f(x)g(x)−1≡0(modxn)(f(x)g(x)−1)2≡0(modx2n)f(x)(2g(x)−g2(x)f(x))≡1(modx2n)
本质为牛顿迭代
设 g(x)=f−1(x),h(g(x))=g−1(x)−f(x)=0。
设已经求得 g0(x),满足 g0(x)≡g(x)(modxn),得:
g(x)≡g0(x)−h(g0(x))h′(g0(x))(modx2n)≡g0(x)−g−10(x)−f(x)−g−20(x)(modx2n)≡2g0(x)−g20(x)f(x)(modx2n)
g(x)=lnf(x)g′(x)=f′(x)f(x)
设 g(x)=ef(x),h(g(x))=lng(x)−f(x)=0。
设已经求得 g0(x),满足 g0(x)≡g(x)(modxn),得:
g(x)≡g0(x)−h(g0(x))h′(g0(x))(modx2n)≡g0(x)−lng0(x)−f(x)g−10(x)(modx2n)≡g0(x)(1−lng0(x)+f(x))(modx2n)
fk(x)=eklnf(x)
可以直接使用多项式幂函数求解,也可以用牛顿迭代求解。
设 g2(x)=f(x),h(g(x))=g2(x)−f(x)=0。
设已经求得 g0(x),满足 g0(x)≡g(x)(modxn),得:
g(x)≡g0(x)−h(g0(x))h′(g0(x))(modx2n)≡g0(x)−g20(x)−f(x)2g0(x)(modx2n)≡g20(x)+f(x)2g0(x)(modx2n)
已知 n 次多项式 f(x) 和 m 次多项式 g(x),求满足 f(x)≡g(x)h(x)+t(x)(modxn+1) 的 n−m 次多项式 h(x) 和次数小于 m 的多项式 t(x)。
设 fr(x) 为多项式 f(x) 系数翻转得到的多项式,得 fr(x)=xnf(x−1)。
f(x)≡g(x)h(x)+t(x)(modxn+1)xnf(x−1)≡xmg(x−1)xn−mh(x−1)+xnt(x−1)(modxn+1)fr(x)≡gr(x)hr(x)+xn−m+1tr(x)(modxn+1)fr(x)≡gr(x)hr(x)(modxn−m+1)hr(x)≡f−1r(x)gr(x)(modxn−m+1)
求出 h(x) 后,得 t(x)≡f(x)−g(x)h(x)(modxm)。
多项式操作的 O(n2) 递推。
F(x)G(x)=1n∑i=0fign−i=[n=0]gn=−1f0n∑i=1fign−i
边界为 g0=inv(f0)。
G(x)=lnF(x)G′(x)=F′(x)F(x)n∑i=0(i+1)gi+1fn−i=(n+1)fn+1(n+1)gn+1f0=(n+1)fn+1−n−1∑i=0(i+1)gi+1fn−ign+1=1(n+1)f0((n+1)fn+1−n−1∑i=0(i+1)gi+1fn−i)gn=1nf0(nfn−n−1∑i=1igifn−i)
G(x)=eF(x)G′(x)=G(x)F′(x)(n+1)gn+1=n∑i=0(i+1)fi+1gn−ign+1=1(n+1)n∑i=0(i+1)fi+1gn−ign=1nn∑i=1ifign−i
边界为 g0=1。
void Inv(int deg,ll *a,ll *b)
{
static ll t[maxn];
if(deg==1)
{
b[0]=qp(a[0],P-2);
return;
}
Inv((deg+1)>>1,a,b);
int lim=calc(deg<<1);
for(int i=0;i<deg;++i) t[i]=a[i];
for(int i=deg;i<lim;++i) t[i]=b[i]=0;
NTT(t,lim,1),NTT(b,lim,1);
for(int i=0;i<lim;++i) b[i]=b[i]*(2-t[i]*b[i]%P+P)%P;
NTT(b,lim,-1);
for(int i=deg;i<lim;++i) b[i]=0;
}
void Ln(int deg,ll *a,ll *b)
{
static ll inva[maxn],dera[maxn];
Inv(deg,a,inva);
for(int i=0;i<deg-1;++i) dera[i]=a[i+1]*(i+1)%P;
dera[deg-1]=0;
int lim=calc(deg<<1);
for(int i=deg;i<lim;++i) dera[i]=inva[i]=0;
NTT(dera,lim,1),NTT(inva,lim,1);
for(int i=0;i<lim;++i) b[i]=dera[i]*inva[i]%P;
NTT(b,lim,-1);
for(int i=deg-1;i>=1;--i) b[i]=b[i-1]*qp(i,P-2)%P;
b[0]=0;
for(int i=deg;i<lim;++i) b[i]=0;
}
void Exp(int deg,ll *a,ll *b)
{
static ll t[maxn],lnb[maxn];
if(deg==1)
{
b[0]=1;
return;
}
Exp((deg+1)>>1,a,b),Ln(deg,b,lnb);
int lim=calc(deg<<1);
for(int i=0;i<deg;++i) t[i]=(a[i]-lnb[i]+P)%P;
for(int i=deg;i<lim;++i) t[i]=b[i]=0;
NTT(t,lim,1),NTT(b,lim,1);
for(int i=0;i<lim;++i) b[i]=b[i]*(1+t[i])%P;
NTT(b,lim,-1);
for(int i=deg;i<lim;++i) b[i]=0;
}
void Pow(int deg,ll *a,ll *b,ll k)
{
static ll lna[maxn];
Ln(deg,a,lna);
for(int i=0;i<deg;++i) lna[i]=lna[i]*k%P;
Exp(deg,lna,b);
}
void Sqrt(int deg,ll *a,ll *b)
{
static ll t[maxn],invb[maxn];
if(deg==1)
{
b[0]=1;
return;
}
Sqrt((deg+1)>>1,a,b);
int lim=calc(deg<<1);
for(int i=0;i<deg;++i) t[i]=2*b[i]%P,invb[i]=0;
for(int i=deg;i<lim;++i) t[i]=invb[i]=0;
Inv(deg,t,invb);
for(int i=0;i<deg;++i) t[i]=a[i];
for(int i=deg;i<lim;++i) t[i]=b[i]=0;
NTT(t,lim,1),NTT(b,lim,1),NTT(invb,lim,1);
for(int i=0;i<lim;++i) b[i]=(b[i]*b[i]%P+t[i])%P*invb[i]%P;
NTT(b,lim,-1);
for(int i=deg;i<lim;++i) b[i]=0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现