多項式總結及模板

1.求逆

設要對多項式A求逆,逆爲B:

求在模ceil(n/2)的逆,將原式與之相減後平方,發現可得在模n意義下也是0了,然後兩邊同乘A,移項即可倍增了(注意此時A也是在模當前長度意義下的)。

最後倍增形式爲B'=2*B-B*B*A  (b’等於2b減b方a),邊界爲常數取逆元,也可發現多項式有無逆取決於常數有無逆元

2.開根

與求逆類似,先求ceil(n/2),然後將A移到左邊使等式右邊變成0,平方,加上4b^2a,再把右邊b^2除到左邊就發現ok了。

最終倍增形式:B'=(A+B*B)/2B(B'等於A加B方後除以2B),除法就上求逆,邊界是常數開根,暴力枚舉(並不會二次剩餘...)?模板題保證是1...

(開根裏面套求逆,雖說複雜度仍然是nlog,但已經比大部分兩個log慢了。。。)

 3.Ln

兩邊求導得到所求的導數B’=A'/A,再積分即可。

4.Exp

B=e^(A)

根據牛頓迭代的那套理論,設一個函數C,使C(B)=0,那麼C(B)=LnB-A

假設已知在mod x^n的B0,要求在mod x^2n的B1

有C(B)=C(B0)/0!+C'(B0)/1!*(B-B0)+...

發現...可以省略,因爲在mod x^n下B是唯一確定的,而mod x^2n下一定也滿足mod x^n下,所以在mod x^2n時後面低的n位與mod x^n相等,當求的導數大於等於二階發現(B-B0)那一項的冪次大於等於2,也就是最小的x項冪次大於等於2n,省略即可。

最終推得

B1=B0-C(B0)/C'(B0)

而C求導時是在把B0這個多項式看成變量求導(不要把每一項的x看成變量),A是已知多項式要看成一個常數

故B1=B0(1-Ln(B0)+A)

倍增即可。(注意能Exp一定要滿足0次項爲0,不然無法賦初值)

 

先貼4個的代碼:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=998244353;
const int N=1e5+100;

void Ad(int &x,int y)
{if((x+=y)>=mod)x-=mod;}
void Mul(int &x,int y)
{x=1LL*x*y%mod;}
int qpow(int x,int y)
{
    int res=1;
    while(y)
    {
        if(y&1)res=1LL*res*x%mod;
        x=1LL*x*x%mod,y>>=1;
    }
    return res;
}

namespace Poly{

vector<int>A,B,C;
int wh[N*3],cc,len,n,inv[N*3];
void Pre_Ntt(int l)
{
    cc=0,len=1;
    while(len<=l)++cc,len<<=1;
}
void Cal_wh()
{for(int i=1;i<len;i++)wh[i]=(wh[i>>1]>>1)|((i&1)<<(cc-1));}
void Ntt(vector<int>&a,bool inv)
{
    for(int i=0;i<len;i++)
        if(i<wh[i])swap(a[i],a[wh[i]]);
    int tp,mo,ha;
    for(int l=2,md;l<=len;l<<=1)
    {
        md=l>>1,tp=qpow(3,(mod-1)/l);
        for(int i=0;i<len;i+=l)
        {
            mo=1;
            for(int j=0;j<md;j++,mo=1LL*mo*tp%mod)
            {
                ha=1LL*mo*a[i+j+md]%mod;
                a[i+j+md]=(a[i+j]-ha+mod)%mod;
                a[i+j]=(a[i+j]+ha)%mod;
            }
        }
    }
    if(inv)
    {
        tp=qpow(len,mod-2);
        for(int i=1;i<len/2;i++)swap(a[i],a[len-i]);
        for(int i=0;i<len;i++)Mul(a[i],tp);
    }
}

void Get_Inv(vector<int>&b,int n)
{
    if(n==1){b[0]=qpow(A[0],mod-2);return;}
    int md=(n+1)/2;
    vector<int>a,c;
    Pre_Ntt(n+md+md),a.resize(len),c.resize(len);
    Get_Inv(c,md);
    Pre_Ntt(n+md+md),Cal_wh();
    for(int i=0;i<n;i++)a[i]=A[i];
    Ntt(a,0),Ntt(c,0);
    for(int i=0;i<len;i++)a[i]=(2*c[i]-1LL*c[i]*c[i]%mod*a[i]%mod+mod)%mod;
    Ntt(a,1);
    for(int i=0;i<n;i++)b[i]=a[i];
}

void Inv(vector<int> &a,vector<int> &res,int n)
{
    A=a,res.clear(),res.resize(n);
    Get_Inv(res,n);
}

void Get_Sqrt(vector<int>&b,int n)
{
    if(n==1){b[0]=1;return;}
    int md=(n+1)/2;
    vector<int>a,c;
    Pre_Ntt(n+n),a.resize(len),c.resize(len);
    Get_Sqrt(c,md);
    for(int i=0;i<n;i++)b[i]=2*c[i]%mod;
    Inv(b,b,n);
    Pre_Ntt(n+n),Cal_wh();
    Ntt(c,0);
    for(int i=0;i<len;i++)c[i]=1LL*c[i]*c[i]%mod;
    Ntt(c,1);
    for(int i=0;i<n;i++)a[i]=(B[i]+c[i])%mod;
    Ntt(a,0),Ntt(b,0);
    for(int i=0;i<len;i++)b[i]=1LL*b[i]*a[i]%mod;
    Ntt(b,1);
}

void Sqrt(vector<int> &a,vector<int> &res,int n)
{
    Pre_Ntt(n+n);
    B=a,res.clear(),res.resize(len);
    Get_Sqrt(res,n);
}

void Dao(vector<int> &a,vector<int> &res,int n)
{
	res.clear(),res.resize(n);
	for(int i=1;i<n;i++)
		res[i-1]=1LL*a[i]*i%mod;
	res[n-1]=0;
}

void Jf(vector<int> &a,vector<int> &res,int n)
{
	res.clear(),res.resize(n+1),inv[1]=1;
	for(int i=2;i<=n;i++)
		inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod;
	for(int i=n-1;i>=0;i--)
		res[i+1]=1LL*a[i]*inv[i+1]%mod;
	res[0]=0;
}

void Ln(vector<int>&a,vector<int> &res,int n)
{
	static vector<int>mo,ha;
	Dao(a,mo,n),Inv(a,ha,n);
	Pre_Ntt(n+n),Cal_wh();
	mo.resize(len),Ntt(mo,0);
	ha.resize(len),Ntt(ha,0);
	for(int i=0;i<len;i++)mo[i]=1LL*mo[i]*ha[i]%mod;
	Ntt(mo,1),Jf(mo,res,n);
}

void Get_Exp(vector<int>&b1,int n)
{
	if(n==1){b1[0]=1;return;}
	int md=(n+1)/2;
	vector<int>b0;
	b0.resize(n),b1.resize(n);
	Get_Exp(b0,md),Ln(b0,b1,n);
	for(int i=0;i<n;i++)b1[i]=((i==0)-b1[i]+C[i]+mod)%mod;
	Pre_Ntt(n+n),b0.resize(len),b1.resize(len);
	Cal_wh(),Ntt(b0,0),Ntt(b1,0);
	for(int i=0;i<len;i++)
		b1[i]=1LL*b0[i]*b1[i]%mod;
	Ntt(b1,1);
}

void Exp(vector<int>&a,vector<int> &res,int n)
{C=a,res.resize(n),Get_Exp(res,n);}

}

int main()
{
    int n;
    scanf("%d",&n);
    vector<int>a,b;
    a.resize(n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    Poly::Exp(a,b,n);
    for(int i=0;i<n;i++)
        printf("%d ",b[i]);
    puts("");
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章