多项式的一些操作

大多数东西只有代码啦
主要是因为数学公式太烦了
代码中\(vc\)指的是\(vector<int>\)
树套树每套一层多一个\(log\)
多项式每套一层不多\(log\).
\(nlog^2n\)的树套树能跑\(2*10^5\),\(nlogn\)的多项式多套几层只能跑\(10^5\)
所以log越多越快
细思极恐


快速傅里叶变换 FFT

经过一番精妙的数学推导得出的

void FFT(Complex *a,int tp){
	for(int i=0;i<Lim;i++)
	if(i<rev[i])swap(a[i],a[rev[i]]);
	for(int pos=1;pos<Lim;pos<<=1){
		Complex w; w.a=cos(pi/pos),w.b=tp*sin(pi/pos);
		for(int R=pos<<1,j=0;j<Lim;j+=R){
			Complex p; p.a=1,p.b=0;
			for(int k=j;k<pos+j;k++,p=p*w){
				Complex x=a[k],y=p*a[k+pos];
				a[k]=x+y,a[k+pos]=x-y;
			}
		}
	}
}

快速数论变换 NTT

void NTT(LL *a,int tp){
	for(int i=0;i<Lim;i++)
	if(i<rev[i])swap(a[i],a[rev[i]]);
	for(int pos=1;pos<Lim;pos<<=1){
		LL w=ksm(3,(P-1)/(pos<<1));
		if(tp==-1)w=ksm(w,P-2);
		for(int R=pos<<1,j=0;j<Lim;j+=R){
			LL p=1;
			for(int k=j;k<j+pos;p=(p*w)%P,k++){
				LL x=a[k],y=(p*a[k+pos])%P;
				a[k]=(x+y)%P,a[k+pos]=(x-y+P)%P;
			}
		}
	}
	if(tp==-1)
	for(int i=0;i<Lim;i++)a[i]=(a[i]*inv)%P;
}

快速沃尔什变换 FWT

\(OR\)卷积
这个其实是\(FMT\)

void FWT_or(LL *a,int tp){
	for(int i=1;i<Lim;i<<=1)
	for(int R=i<<1,j=0;j<Lim;j+=R)
	for(int k=j;k<j+i;k++)
	(a[k+i]+=a[k]*(LL)tp+P)%=P;
}

\(AND\)卷积
江道理应该把每一位反过来然后做\(FMT\)

void FWT_and(LL *a,int tp){
	for(int i=1;i<Lim;i<<=1)
	for(int R=i<<1,j=0;j<Lim;j+=R)
	for(int k=j;k<j+i;k++)
	(a[k]+=a[k+i]*(LL)tp+P)%=P;
}

\(XOR\)卷积
\(This~is~true~FWT!\)

void FWT_xor(LL *a,int tp){
	for(int i=1;i<Lim;i<<=1)
	for(int R=i<<1,j=0;j<Lim;j+=R)
	for(int k=j;k<j+i;k++){
		LL x=a[k],y=a[k+i];
		a[k]=(x+y)%P,a[k+i]=(x-y+P)%P;
		if(tp==-1)(a[k]=a[k]*inv2%P),(a[k+i]=a[k+i]*inv2%P);
	}
}

快速莫比乌斯变换 FMT

本质是高维前缀和

void FMT(int *a){
	for(int i=0;i<Lim;i++)
	for(int j=0;j<n;j++)
	if(j>>i&1)a[j]=(a[j]+a[j^(1<<i)])%P;
}

多项式求逆

直接倍增就好了

void solve(){
	bin[0]=n;
	for(cnt=1;;cnt++){
		bin[cnt]=(bin[cnt-1]+1)/2;
		if(bin[cnt]==1)break;
	}
	g[0]=ksm(f[0],P-2),NTT(f,1);
	for(rg i=cnt-1;~i;i--){
		for(rg j=bin[i+1];j<Lim;j++)g[j]=0;
		for(rg j=0;j<bin[i+1];j++){
			h[j]=(g[j]<<1);
			if(h[j]>P)h[j]-=P;
		}
		NTT(g,1);
		for(rg j=0;j<Lim;j++)
		g[j]=(g[j]*g[j]%P*f[j])%P;
		NTT(g,-1);
		for(rg j=0;j<bin[i];j++)
		g[j]=(h[j]-g[j]+P)%P;
	}
}

多项式微分

void diff(vc &a){
    int len=a.size()-1;
    for(int i=0;i<len-1;i++)a[i]=1ll*a[i+1]*(i+1)%P;
    a[len]=0,a.resize(len);
}

多项式积分

void inte(vc &a){
    int len=a.size();
    a.resize(len+1);
    for(int i=len;i;i--)
    a[i]=1ll*a[i-1]*ksm(i,P-2)%P;
    a[0]=0;
}

这两个是基本操作


多项式求\(ln\)

牛顿迭代就行了.

vc getln(vc a,int n){
    vc g=getinv(a,n);
    diff(a);
    mul(g,a),inte(g);
    return g;
}

多项式\(exp\)

常数巨大还在卡常
如果你那么想看代码板子里有.


板子

这里默认对998244353取模
即拉即用造福社会

namespace poly{
    typedef vector<int> vc; vc h; 
    int mi[41],iv[41],bin[41],inv,len,Lim,rev[N],cnt;
    int ksm(int a,int p){
        int res=1;
        while(p){
            if(p&1)res=1ll*res*a%P;
            a=1ll*a*a%P,p>>=1;
        }
        return res;
    }
    void init(){
        for(int i=0;(1<<i)<=P-1;i++)mi[i]=ksm(3,(P-1)/(1<<i)),iv[i]=ksm(mi[i],P-2);
    }
    void init_p(int S){
        len=0;
        for(Lim=1;Lim<=S;Lim<<=1)len++; inv=ksm(Lim,P-2);
        for(int i=0;i<Lim;i++)
        rev[i]=(rev[i>>1]>>1)|((i&1)<<(len-1));
    }
    void NTT(vc &a,int tp){
        a.resize(Lim);
        for(rg i=0;i<Lim;i++)
        if(i<rev[i])swap(a[i],a[rev[i]]); 
        for(rg pos=1,s=1;pos<Lim;pos<<=1,s++){
            int w=(tp==1)?mi[s]:iv[s];
            for(rg R=pos<<1,j=0;j<Lim;j+=R){
                int p=1;
                for(rg k=j;k<j+pos;p=1ll*p*w%P,k++){
                    int x=a[k],y=1ll*p*a[k+pos]%P;
                    a[k]=(x+y)%P,a[k+pos]=(x-y+P)%P;
                }
            }
        } 
        if(tp==-1)
        for(int i=0;i<Lim;i++)a[i]=(1ll*a[i]*inv)%P;
    }
    void mul(vc &a,vc b){
        init_p(a.size()+b.size()+1);
        a.resize(Lim),b.resize(Lim);
        NTT(a,1),NTT(b,1);
        for(int i=0;i<Lim;i++)a[i]=1ll*a[i]*b[i]%P;
        NTT(a,-1);
    }
    void mul2(vc &a,vc b){
        init_p(2*a.size()+b.size()+1);
        NTT(a,1),NTT(b,1);
        for(int i=0;i<Lim;i++)a[i]=1ll*a[i]*a[i]%P*b[i]%P;
        NTT(a,-1);
    }
    vc getinv(vc f,int n){
        bin[0]=n;
        for(cnt=1;;cnt++){
            bin[cnt]=(bin[cnt-1]+1)/2;
            if(bin[cnt]==1)break;
        }
        vc tmp,g; g.resize(1);
        g[0]=ksm(f[0],P-2); 
        for(rg i=cnt-1;~i;i--){
            h.resize(bin[i]);
            for(rg j=0;j<bin[i+1];j++){
                h[j]=(g[j]<<1);
                if(h[j]>P)h[j]-=P;
            }
            tmp.resize(bin[i]);
            for(rg j=0;j<bin[i];j++)tmp[j]=f[j];
            mul2(g,tmp),g.resize(bin[i]);
            for(rg j=0;j<bin[i];j++)
            g[j]=(h[j]-g[j]+P)%P;
        }
        return g;
    }
    void diff(vc &a){
        int len=a.size()-1;
        for(int i=0;i<len-1;i++)a[i]=1ll*a[i+1]*(i+1)%P;
        a[len]=0,a.resize(len);
    }
    void inte(vc &a){
        int len=a.size();
        a.resize(len+1);
        for(int i=len;i;i--)
        a[i]=1ll*a[i-1]*ksm(i,P-2)%P;
        a[0]=0;
    }
    vc getln(vc a,int n){
    	a.resize(n+1);
        vc g=getinv(a,n);
        diff(a);
        mul(g,a),inte(g);
        g.resize(n+1);
        return g;
    }
    vc getexp(vc f,int n){
    	int bn[41],cnt=0;
    	bn[0]=n*2;
    	for(cnt=1;;cnt++){
    		bn[cnt]=(bn[cnt-1]-1)/2+1;
    		if(bn[cnt]==1)break;
    	}
    	vc g; g.resize(1),g[0]=1;
    	for(int i=cnt-1;~i;i--){
    		vc tmp=getln(g,bn[i]);
    		for(int j=0;j<bn[i];j++)
    		tmp[j]=((f[j]-tmp[j])%P+P)%P;
    		tmp[0]=(tmp[0]+1)%P;
    		mul(g,tmp);
    		g.resize(bn[i]);
    	}
    	return g;
    }
}
posted @ 2018-11-30 15:07  Romeolong  阅读(281)  评论(0编辑  收藏  举报