zoukankan      html  css  js  c++  java
  • 【模板】分治FFT

    蒟蒻写题解实在不易

    前置

    方法一:(Cdq+NTT)
    方法二:多项式求逆
    NTT总结多项式求逆总结

    方法一

    (Cdq+NTT)

    [f_i=sumlimits_{j=1}^i f_{i-j}g_j ]

    乍一看直接(cdq),然后发现树状数组类的东西好像做不了:$$[l,mid]longrightarrow [mid+1,r]:w_x=sumlimits_{i=l}^{mid(x)} f_i g_{x-i}$$

    直接上卷积就行,(O(nlog^2n))

    毒瘤的代码时间,由于我们是只把利用到的位置进行(NTT),才保证了复杂度

    期间多个下标混合利用,细节很多,调了很久,建议先把思路完全理清再写代码

    方法二

    多项式求逆:

    [g_0=0 herefore sumlimits_{j=1}^i f_{i-j}g_j=sumlimits_{j=0}^i f_{i-j}g_j ]

    构造生成函数:(F(x)in f,G(x)in g)

    则:$$F(x)G(x)+1=F(x)longrightarrow F(x)equiv frac{-1}{G(x)-1}(mod~x^n)$$

    直接多项式求逆,(O(nlogn))

    Code(方法一)

    #include<bits/stdc++.h>
    typedef long long LL;
    const LL mod=998244353,gg=3,maxn=1e6+9;
    inline LL Read(){
    	LL x(0),f(1); char c=getchar();
    	while(c<'0' || c>'9'){
    		if(c=='-') f=-1; c=getchar();
    	}
    	while(c>='0' && c<='9'){
    		x=(x<<3)+(x<<1)+c-'0'; c=getchar();
    	}
    	return x*f;
    }
    inline LL Pow(LL base,LL b){
    	LL ret(1);
    	while(b){
    		if(b&1) ret=ret*base%mod; base=base*base%mod; b>>=1;
    	}return ret;
    }
    LL r[maxn];
    inline void NTT(LL *a,LL n,LL type){
    	for(LL i=0;i<n;++i) if(i<r[i]) std::swap(a[i],a[r[i]]);
    	for(LL mid=1;mid<n;mid<<=1){
    		LL wn(Pow(gg,(mod-1)/(mid<<1)));
    		if(type==-1) wn=Pow(wn,mod-2);
    		for(LL R=mid<<1,j=0;j<n;j+=R)
    			for(LL k=0,w=1;k<mid;++k,w=w*wn%mod){
    				LL x(a[j+k]),y(w*a[j+mid+k]%mod);
    				a[j+k]=(x+y)%mod; a[j+mid+k]=(x-y+mod)%mod;
    			}
        }
    	if(type==-1){
    		LL ty(Pow(n,mod-2));
    		for(LL i=0;i<n;++i) a[i]=a[i]*ty%mod;
    	}
    }
    inline LL Fir(LL n){
    	LL limit(1),len(0);
    	while(limit<n){
    		limit<<=1; ++len;
    	}
    	for(LL i=0;i<limit;++i) r[i]=(r[i>>1]>>1)|((i&1)<<len-1);
    	return limit;
    }
    LL n;
    LL f[maxn],g[maxn],F[maxn],G[maxn],W[maxn];
    inline void Solve(LL l,LL r){
    	if(l==r) return;
    	LL mid(l+r>>1);
    	Solve(l,mid);
    	for(LL i=l,x=0;i<=mid;++i,++x) F[x]=f[i];
    	for(LL i=1,x=0;i<=r-l;++i,++x) G[x]=g[i];
    
    	LL limit(Fir(r-l+mid-l+1));
    	for(LL i=mid-l+1;i<limit;++i) F[i]=0;
    	for(LL i=r-l-1+1;i<limit;++i) G[i]=0;
    	NTT(F,limit,1); NTT(G,limit,1);
    	for(LL i=0;i<limit;++i) W[i]=F[i]*G[i]%mod;
    	NTT(W,limit,-1);
    
    	for(LL i=mid+1,x=mid-l;i<=r;++i,++x) f[i]=(f[i]+W[x])%mod;
    	Solve(mid+1,r);
    }
    int main(){
    	n=Read();
    	for(LL i=1;i<n;++i) g[i]=Read();
    	f[0]=1;
    	Solve(0,n-1);
    	for(LL i=0;i<n;++i) printf("%lld ",f[i]);
    	return 0;
    }
    
  • 相关阅读:
    实验四 决策树算法及应用
    实验三 朴素贝叶斯算法及应用
    实验二 K近邻算法及应用
    实验一 感知器及其应用
    实验三 面向对象分析与设计
    实验二 结构化分析与设计
    实验一 软件的开发文档与工具的安装与使用
    ATM管理系统
    举例分析流程图与活动图的区别与联系
    四则运算
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10696022.html
Copyright © 2011-2022 走看看