• 多项式


    形如 (f(x)=a_0x^0+a_1x^1+a_2x^2+ dots +a_{n-1}x^{n-1})

    点值表示法:通过代入 (n) 个不同的值 (x_0,x_1 dots x_{n-1})(f(x)) 中,得到 (y_0,y_1...y_{n-1}),用 ((x_0,y_0),(x_1,y_1) dots (x_{n-1},y_{n-1})) 即可表示这个多项式。

    若用点值表示法,并且两个多项式的 (x) 对应相等,那么将 (y) 对应相乘,即可 (O(n)) 的得到它们乘积的点值表示法。

    从多项式的系数表示向点值表示的转化,称为求值,从多项式的点值表示向系数表示的转化,称为插值。

    FFT

    快速傅里叶变换可以做到 (O(nlog n)) 进行求值和插值。

    复数相乘,模长相乘,幅角相加。

    [large (a+bi)×(c+di)=(ac-bd)+(bc+ad)i ]

    在复平面上,以原点为圆心,(1) 为半径作圆,所得的圆叫单位圆。以圆点为起点,圆的 (n) 等分点为终点,做 (n) 个向量,设幅角为正且最小的向量对应的复数为 (ω_n),称为 (n) 次单位根。

    [largeegin{aligned} &ω_n^k=cosfrac{2πk}{n}+isinfrac{2πk}{n} \ &ω_{2n}^{2k}=ω_n^k \ &ω_{n}^{k+frac{n}{2}}=-ω_n^k end{aligned} ]

    [large f(x)=a_0x^0+a_1x^1+a_2x^2+a_3x^3+ dots +a_{n-2}x^{n-2}+a_{n-1}x^{n-1} ]

    进行奇偶分类得:

    [largeegin{aligned} f1(x)=a_0+a_2x^1+a_4x^2+a_6x^3+ dots +a_{n-2}x^{frac{n}{2}-1}\ f2(x)=a_1+a_3x^1+a_5x^2+a_7x^3+ dots +a_{n-1}x^{frac{n}{2}-1} end{aligned} ]

    (f(x)=f1(x^2)+xf2(x^2))

    (k<frac{n}{2}),代入 (ω_n^k) 得:

    [large f(ω_n^k)=f1(ω_n^{2k})+ω_n^kf2(ω_n^{2k}) ]

    再代入 (ω_n^{k+frac{n}{2}})

    [large f(ω_n^{k+frac{n}{2}})=f1(ω_n^{2k})-ω_n^kf2(ω_n^{2k}) ]

    通过这两个式子,我们就可以进行递归求解了,但因递归常数过大,我们通过迭代来实现。

    我们将原多项式系数重新排序,将每个系数都在它递归的最后位置,就可以用迭代来代替递归实现。

    发现原来在第 (a) 个位置的系数,在递归的最后位置为 (a) 的二进制反转以后的数。

    这称为蝴蝶操作。

    代入 (ω_n^{-k}),可再次求得一系列值,将其除以 (n) 即可求得多项式相乘后的系数表示。

    struct Complex
    {
    	double x,y;
    	Complex(double a=0,double b=0)
    	{
    		x=a,y=b;
    	}
    }f[maxn],g[maxn];
    Complex operator +(const Complex &a,const Complex &b)
    {
    	return Complex(a.x+b.x,a.y+b.y);
    }
    Complex operator -(const Complex &a,const Complex &b)
    {
    	return Complex(a.x-b.x,a.y-b.y);
    }
    Complex operator *(const Complex &a,const Complex &b)
    {
    	return Complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
    }
    int calc(int n)
    {
        int lim=1;
        while(lim<=n) lim<<=1;
        for(int i=0;i<lim;++i)
            rev[i]=(rev[i>>1]>>1)|((i&1)?lim>>1:0);
        return lim;
    }
    void FFT(Complex *a,int lim,int type)
    {
    	for(int i=0;i<lim;++i)
            if(i<rev[i])
                swap(a[i],a[rev[i]]);
    	for(int len=1;len<lim;len<<=1)
    	{
    		Complex T(cos(Pi/len),type*sin(Pi/len));
    		for(int i=0;i<lim;i+=len<<1)
    		{
    			Complex t(1,0);
    			for(int j=i;j<i+len;++j,t=t*T)
    			{
    				Complex x=a[j],y=t*a[j+len];
    				a[j]=x+y,a[j+len]=x-y;
    			}
    		}
    	}
        if(type==1) return;
        for(int i=0;i<lim;++i) a[i].x=a[i].x/lim+0.5;
    }
    void mul(Complex *f,Complex *g)
    {
        int lim=calc(n+m);
        FFT(f,lim,1),FFT(g,lim,1);
        for(int i=0;i<lim;++i) f[i]=f[i]*g[i];
        FFT(f,lim,-1);
    }
    

    NTT

    (a,p) 互素,且 (p>1),对于 (a^n equiv 1 pmod{m}) 最小的 (n),称为 (a)(p) 的阶,记作 (δ_p(a))

    (p) 是正整数,(a) 是整数,若 (δ_p(a)=varphi(p)),则称 (a) 为模 (p) 的一个原根。

    原根个数不唯一。

    (P) 为素数,设 (G)(P) 的原根,那么 (G^i mod P,(i<G<P,0<i<P)) 的结果两两不同。

    模数有 (998244353,1004535809,469762049),原根都为 (3)

    [large ω_n equiv g^{frac{p-1}{n}} pmod{p} ]

    int calc(int n)
    {
        int lim=1;
        while(lim<=n) lim<<=1;
        for(int i=0;i<lim;++i)
            rev[i]=(rev[i>>1]>>1)|((i&1)?lim>>1:0);
        return lim;
    }
    void NTT(ll *a,int lim,int type)
    {
        for(int i=0;i<lim;++i)
            if(i<rev[i])
                swap(a[i],a[rev[i]]);
        for(int len=1;len<lim;len<<=1)
        {
            ll wn=qp(type==1?G:Gi,(P-1)/(len<<1));
            for(int i=0;i<lim;i+=len<<1)
            {
                ll w=1;
                for(int j=i;j<i+len;++j,w=w*wn%P)
                {
                    ll x=a[j],y=w*a[j+len]%P;
                    a[j]=(x+y)%P,a[j+len]=(x-y+P)%P;
                }
            }
        }
        if(type==1) return;
        ll inv=qp(lim,P-2);
        for(int i=0;i<lim;++i) a[i]=a[i]*inv%P;
    }
    void mul(ll *f,ll *g)
    {
        int lim=calc(n+m);
        NTT(f,lim,1),NTT(g,lim,1);
        for(int i=0;i<lim;++i) f[i]=f[i]*g[i]%P;
        NTT(f,lim,-1);
    }
    

    多项式求导和积分

    [largeegin{aligned} left [ x^i ight ] {f}'(x) &= (i+1) left [ x^{i+1} ight ]f(x) \ left [ x^i ight ] int f(x) &= frac{1}{i} left [ x^{i-1} ight ]f(x) end{aligned} ]

    多项式牛顿迭代

    已知 (f(x)),求 (g(x)),满足 (f(g(x)) equiv 0 pmod{x^n})

    设已经求得 (g_0(x)),满足 (g_0(x) equiv g(x) pmod{x^n}),由泰勒展开得:

    [largeegin{aligned} 0 &= f(g(x)) \ &= f(g_0(x)) + {f}'(g_0(x))(g(x)-g_0(x)) + frac{{f}''(g_0(x))}{2}(g(x)-g_0(x))^2+ dots \ & equiv f(g_0(x)) + {f}'(g_0(x))(g(x)-g_0(x)) pmod{x^{2n}} end{aligned} ]

    得:

    [large g(x) equiv g_0(x) - frac{f(g_0(x))}{{f}'(g_0(x))} pmod{x^{2n}} ]

    多项式求逆

    [large f(x)g(x) equiv 1 pmod{x^n} ]

    (g(x))(f(x)) 的逆元,模 (x^n) 的意义是将次数大于等于 (n) 的项都忽略掉。

    设已经求得满足

    [large f(x)g(x) equiv 1 pmod{x^n} ]

    (g(x)),得:

    [large egin{aligned} f(x)g(x) - 1 &equiv 0 pmod{x^n} \ (f(x)g(x)-1)^2 &equiv 0 pmod{x^{2n}} \ f(x)(2g(x)-g^2(x)f(x)) &equiv 1 pmod{x^{2n}} end{aligned} ]

    本质为牛顿迭代

    (g(x) = f^{-1}(x))(h(g(x)) = g^{-1}(x) - f(x) =0)

    设已经求得 (g_0(x)),满足 (g_0(x) equiv g(x) pmod{x^n}),得:

    [largeegin{aligned} g(x) & equiv g_0(x) - frac{h(g_0(x))}{{h}'(g_0(x))} pmod{x^{2n}} \ & equiv g_0(x) - frac{g^{-1}_0(x)-f(x)}{-g^{-2}_0(x)} pmod{x^{2n}} \ & equiv 2g_0(x) - g_0^2(x)f(x) pmod{x^{2n}} end{aligned} ]

    多项式对数函数

    [largeegin{aligned} g(x) &= ln f(x) \ {g}' (x) &= frac{{f}' (x)}{f(x)} end{aligned} ]

    多项式指数函数

    (g(x) = e^{f(x)})(h(g(x)) = ln g(x) - f(x) =0)

    设已经求得 (g_0(x)),满足 (g_0(x) equiv g(x) pmod{x^n}),得:

    [largeegin{aligned} g(x) & equiv g_0(x) - frac{h(g_0(x))}{{h}'(g_0(x))} pmod{x^{2n}} \ & equiv g_0(x) - frac{ln g_0(x)-f(x)}{g^{-1}_0(x)} pmod{x^{2n}} \ & equiv g_0(x)(1 - ln g_0(x)+f(x)) pmod{x^{2n}} end{aligned} ]

    多项式幂函数

    [large f^k(x) = e^{k ln f(x)} ]

    多项式开根

    可以直接使用多项式幂函数求解,也可以用牛顿迭代求解。

    (g^2(x) = f(x))(h(g(x)) = g^2(x) - f(x) =0)

    设已经求得 (g_0(x)),满足 (g_0(x) equiv g(x) pmod{x^n}),得:

    [largeegin{aligned} g(x) & equiv g_0(x) - frac{h(g_0(x))}{{h}'(g_0(x))} pmod{x^{2n}} \ & equiv g_0(x) - frac{ g_0^2(x)-f(x)}{2g_0(x)} pmod{x^{2n}} \ & equiv frac{ g_0^2(x)+f(x)}{2g_0(x)} pmod{x^{2n}} end{aligned} ]

    多项式除法

    已知 (n) 次多项式 (f(x))(m) 次多项式 (g(x)),求满足 (f(x) equiv g(x)h(x)+t(x) pmod{x^{n+1}})(n-m) 次多项式 (h(x)) 和次数小于 (m) 的多项式 (t(x))

    (f_r(x)) 为多项式 (f(x)) 系数翻转得到的多项式,得 (f_r(x) = x^nf(x^{-1}))

    [largeegin{aligned} f(x) &equiv g(x)h(x)+t(x) pmod{x^{n+1}} \ x^n f(x^{-1}) &equiv x^m g(x^{-1}) x^{n-m} h(x^{-1}) + x^n t(x^{-1}) pmod{x^{n+1}} \ f_r(x) &equiv g_r(x)h_r(x) + x^{n-m+1} t_r(x) pmod{x^{n+1}} \ f_r(x) &equiv g_r(x)h_r(x) pmod{x^{n-m+1}} \ h_r(x) &equiv f_r^{-1}(x)g_r(x) pmod{x^{n-m+1}} end{aligned} ]

    求出 (h(x)) 后,得 (t(x) equiv f(x) - g(x)h(x) pmod{x^m})

    递推

    多项式操作的 (O(n^2)) 递推。

    多项式求逆

    [largeegin{aligned} F(x)G(x)&=1 \ sum_{i=0}^nf_ig_{n-i}&=[n=0] \ g_n&=-frac{1}{f_0}sum_{i=1}^nf_ig_{n-i} end{aligned} ]

    边界为 (g_0=inv(f_0))

    多项式对数函数

    [largeegin{aligned} G(x)&=ln F(x) \ {G}'(x)&=frac{{F}'(x)}{F(x)} \ sum_{i=0}^n(i+1)g_{i+1}f_{n-i}&=(n+1)f_{n+1} \ (n+1)g_{n+1}f_0&=(n+1)f_{n+1}-sum_{i=0}^{n-1}(i+1)g_{i+1}f_{n-i} \ g_{n+1}&=frac{1}{(n+1)f_0}left( (n+1)f_{n+1}-sum_{i=0}^{n-1}(i+1)g_{i+1}f_{n-i} ight)\ g_n&=frac{1}{nf_0}left( nf_n-sum_{i=1}^{n-1}ig_if_{n-i} ight)\ end{aligned} ]

    多项式指数函数

    [largeegin{aligned} G(x)&=e^{F(x)} \ {G}'(x)&=G(x){F}'(x) \ (n+1)g_{n+1}&=sum_{i=0}^n(i+1)f_{i+1}g_{n-i} \ g_{n+1}&=frac{1}{(n+1)}sum_{i=0}^n(i+1)f_{i+1}g_{n-i} \ g_n&=frac{1}{n}sum_{i=1}^nif_ig_{n-i} \ end{aligned} ]

    边界为 (g_0=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;
    }
    
  • 相关阅读:
    通过前序遍历和中序遍历确定二叉树,并输出后序遍历序列
    浅谈c语言和c++中struct的区别
    KFCM算法的matlab程序
    聚类——KFCM
    FCM算法的matlab程序2
    GMM算法的matlab程序
    FCM算法的matlab程序
    K-means算法的matlab程序
    GMM算法的matlab程序(初步)
    FCM算法的matlab程序(初步)
  • 原文地址:https://www.cnblogs.com/lhm-/p/12229547.html
Copyright © 2020-2023  润新知