多项式

FFT

简单来说做的就是多项式乘法,能够将多项式乘法的时间复杂度从 o(n2) 优化至 o(nlogn) 。其思想就是将多项式由系数表示法转化为点值表示法,快速求出新多项式的点值表示,再将其转化为系数表示法。

f(x)=a0+a1x+a2x2+.......+an1xn1

将多项式按照奇偶项分开

f(x)=(a0+a2x2+......+an2xn2)+(a1x+a3x3+......+an1xn1)

f(x)=(a0+a2x2+......+an2xn2)+x(a1+a3x2+......+an1xn2)

每次选择单位圆上的点所表示的复数带入计算即可。
可以发现一个规律:系数不断递归下去最终的位置将会是其二进制翻转后所表示的数。
代码模板如下:

inline void FFT(cp *a,int n,int inv) {
    while(t<=n) t<<=1; while((1<<bit)<t) bit++;
    for(int i=0;i<t;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<bit-1);
    for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
    for(int mid=1;mid<n;mid*=2) {
        cp w=cp{cos(pi/mid),inv*sin(pi/mid)};
        for(int i=0;i<n;i+=2*mid) {
            cp o=cp{1,0};
            for(int j=0;j<mid;j++,o=o*w) {
                cp x=a[i+j], y=o*a[i+j+mid];
                a[i+j]=x+y; a[i+j+mid]=x-y;
            }
        }
    }  
}

NTT

整数 FFT ,就是用原根代替单位根,其余同 FFT

3114514 为模数 998244353 的原根。

找原根的方法:

将模数 P1 分解质因数为 i=1mpici ,则 gP 的原根当且仅当 i[1,m] 都满足 gP1pi1(modP)

模板如下

inline void NTT(LL *a,int n,int pd) {
    for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
    LL w,o,x,y;
    for(int mid=1;mid<n;mid<<=1) {
        w=Power(114514,(P-1)/(mid<<1));
        for(int i=0;i<n;i+=(mid<<1)) {
            o=1;
            for(int j=0;j<mid;j++,o=o*w%P) {
                x=a[i+j]; y=o*a[i+j+mid]%P;
                a[i+j]=(x+y)%P; a[i+j+mid]=(x-y+P)%P;
            } 
        }
    }
    if(pd==-1) {
        reverse(a+1,a+n); LL s=Power(n,P-2);
        for(int i=0;i<n;i++) a[i]=a[i]*s%P;
    }
}

导数

定义:函数在某一点的导数就是该函数所代表的曲线在这一点上的切线斜率 byBaidu

常用导数

f(x)=cf(x)=0

f(x)=axf(x)=axlna

f(x)=exf(x)=ex

f(x)=xcf(x)=cxc1

f(x)=lnxf(x)=1x

f(x)=sinxf(x)=cosx

f(x)=cosxf(x)=sinx

(f(g(x)))=f(g(x))g(x)

泰勒展开式

f(x)=i=0+f(x0)(i)(xx0)ii!

牛顿迭代

已知 G(x) ,求 F(x) 满足

G(F(x))0(modxn)

考虑倍增,假设我们现在已经求出了 G(Fn(x))0(modxn) ,我们要凭借此推出 G(F2n(x))0(modx2n)
易知,肯定满足有

Fn(x)F2n(x)(modxn)

则两多项式相减后在模 xn 的意义下最低非零项为 anxn 。所以

(F2n(x)Fn(x))20(modx2n)

G(F2n(x))Fn(x) 处泰勒展开

G(f2n(x))G(Fn(x))+G(Fn(x))(F2n(x)Fn(x))+G(Fn(x))2(F2n(x)Fn(x))2+.......(modx2n)

G(f2n(x))G(Fn(x))+G(Fn(x))(F2n(x)Fn(x))(modx2n)

F2n(x)Fn(x)G(Fn(x))G(Fn(x))(modx2n)

倍增处理就完事了

多项式求逆

给定 G(x) ,求 F(x) 满足 F(x)G(x)1(modxn)

考虑倍增,假设我们已经求出 Fn(x)G(x)1(modxn) ,现在我们要求出 F2n(x)G(x)1(modx2n)

首先有

Fn(x)F2n(x)(modxn)

那么

(F2n(x)Fn(x))20(modx2n)

在等式两边同时乘上 G(x)

(F2n(x)22F2n(x)Fn(x)+Fn(x)2)(G(x))0(modx2n)

因为 F2n(x)G(x)1(modx2n)

(F2n(x)2Fn(x)+Fn(x)2)G(x)0(modx2n)

F2n(x)=Fn(x)(2Fn(x)G(x))(modx2n)

inline void Inv(int n,LL *G,LL *f) {
    if(n==1) { f[0]=Power(G[0],P-2); return ; }
    Inv((n+1)>>1,G,f);
    t=1; bit=0;
    while(t<(n<<1)) t<<=1; while((1<<bit)<t) bit++;
    for(int i=1;i<t;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<bit-1);
    for(int i=0;i<n;i++) g[i]=G[i];
    for(int i=n;i<t;i++) g[i]=0;
    FFT(f,t,1); FFT(g,t,1);
    for(int i=0;i<t;i++) f[i]=f[i]*(2LL-f[i]*g[i]%P+P)%P;
    FFT(f,t,-1);
    for(int i=n;i<t;i++) f[i]=0;
}

多项式除法

给定多项式 A(x)B(x) ,求 D(x)R(x) ,满足 A(x)=B(x)D(x)+R(x)

令多项式最高次幂指数为 deg 。不妨设 deg(A(x))=n,deg(B(x))=m,deg(D(x))=nm,deg(R(x))=m1

可以发现一个性质: xdeg(F(x))F(1x) 就是将 F(x) 系数翻转所得的多项式,记为 FR(x)

A(1x)=B(1x)D(1x)+R(1x)

xnA(1x)=xmB(1x)xnmD(1x)+xnm+1(xm1R(1x))

AR(x)=BR(x)DR(x)+xnm+1RR(x)

AR(x)BR(x)DR(x)(modxnm+1)

由于 deg(D(x))=nmnm+1 ,故此时求出来的 D(x) 是真实的。

多项式 ln

给定 G(x)F(x) 满足 F(x)lnG(x)(modxn)

两边同时求导

F(x)=(lnG(x))=1G(x)G(x)(modxn)

F(x)=G(x)G(x)(modxn)

F(x) 常数项为 0G(x) 常数项为 1

多项式 exp

给定 G(x) ,求 F(x) 满足 F(x)eG(x)(modxn)

两边同时取 ln

ln(F(x))G(x)(modxn)

ln(F(x))G(x)0(modxn)

令函数 P(X)=lnXG(x) ,在这里我们将 G(x) 视为一个常函数。套牛顿迭代的式子。

F2n(x)Fn(x)P(Fn(x))P(Fn(x))Fn(x)(ln(Fn(x))G(x))Fn(x)(modx2n)

F(x) 的常数项为 1G(x) 的常数项为 0

posted @   _YangZJ  阅读(106)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
主题色彩