zoukankan      html  css  js  c++  java
  • 多项式的一些操作

    大多数东西只有代码啦
    主要是因为数学公式太烦了
    代码中(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;
        }
    }
    
  • 相关阅读:
    bootstrap-table 切换页码保留勾选的checkbox
    vsftp服务器同步文件
    MySQL5.7 主从复制配置
    VMware NAT模式下设置网络
    在Jsp中调用静态资源,路径配置问题,jsp获取路径的一些方法
    centos7.3安装配置vsftp
    Linux安装配置Nginx
    jsp登录页面,展示错误信息,刷新页面后错误依然存在解决方案
    linux中使用Jmeter压测总结
    常规测试方法
  • 原文地址:https://www.cnblogs.com/Romeolong/p/10044268.html
Copyright © 2011-2022 走看看