zoukankan      html  css  js  c++  java
  • 分治FFT

    分治FFT


    引入问题:摘自洛谷P4721 【模板】分治 FFT,描述如下:

    给出多项式(g[0..n]),求多项式(f),满足:

    [f(i)=sum_{j=1}^if(i-j)g(j) ]

    边界(f(0)=1)


    注意到这是个卷积的形式,不难想到(FTT),但是这里卷积内有一个(f)(f)是未知的,就不能用常规的多项式乘法了。

    我们引入一个叫做分治(FFT)的算法,其基本思想很简单,就是和(cdq)分治一样,我们先分治左边,然后考虑左边对右边的影响,再分治右边。

    具体的,假设我们现在已经做完了([l,mid]),考虑对右边的影响。

    我们可以把式子列出来,就是:

    [f(i)=sum_{j=l}^{mid}f(j)g(i-j) ]

    那么我们可以把(f)([l,mid])项拿出来,其他项置(0),在把这个和(g)([0,r-l])卷起来就可以得到影响,然后加上去就好了。

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    #define ll long long 
    
    const int maxn = 2e5+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 998244353;
    
    int f[maxn],g[maxn],mxn,w[maxn],n,N,rw[maxn],t[maxn],bit,pos[maxn],s[maxn];
    
    int qpow(int a,int x) {
    	int res=1;
    	for(;x;x>>=1,a=1ll*a*a%mod) if(x&1) res=1ll*res*a%mod;
    	return res;
    }
    
    void prepare() {
    	w[0]=1;w[1]=qpow(3,(mod-1)/mxn);
    	for(int i=2;i<=mxn;i++) w[i]=1ll*w[i-1]*w[1]%mod;
    	rw[0]=1,rw[1]=qpow(qpow(3,mod-2),(mod-1)/mxn);
    	for(int i=2;i<=mxn;i++) rw[i]=1ll*rw[i-1]*rw[1]%mod;
    }
    
    void ntt(int *r,int op) {
    	for(int i=1;i<N;i++) if(pos[i]>i) swap(r[i],r[pos[i]]);
    	for(int i=1,d=mxn>>1;i<N;i<<=1,d>>=1) 
    		for(int j=0;j<N;j+=i<<1)
    			for(int k=0;k<i;k++) {
    				int x=r[j+k],y=1ll*r[i+j+k]*(op==1?w:rw)[k*d]%mod;
    				r[j+k]=(x+y)%mod,r[i+j+k]=(x-y+mod)%mod;
    			}
    	if(op==-1) {
    		int inv=qpow(N,mod-2);
    		for(int i=0;i<N;i++) r[i]=1ll*r[i]*inv%mod;
    	}
    }
    
    void solve(int l,int r) {
    	if(l==r) return ;
    	int mid=(l+r)>>1;
    	solve(l,mid);
    	for(int i=l;i<=mid;i++) t[i-l]=f[i],s[i-l]=g[i-l];
    	for(int i=mid+1;i<=r;i++) t[i-l]=0,s[i-l]=g[i-l];
    	for(bit=0,N=1;N<=r-l;N<<=1,bit++);
    	for(int i=r-l+1;i<N;i++) t[i]=s[i]=0;
    	for(int i=1;i<N;i++) pos[i]=pos[i>>1]>>1|((i&1)<<(bit-1));
    	ntt(s,1),ntt(t,1);
    	for(int i=0;i<N;i++) s[i]=1ll*s[i]*t[i]%mod;
    	ntt(s,-1);
    	for(int i=mid+1;i<=r;i++) f[i]=(f[i]+s[i-l])%mod;
    	solve(mid+1,r);
    }
    
    int main() {
    	read(n);
    	for(int i=1;i<n;i++) read(g[i]);f[0]=1;
    	for(mxn=1;mxn<n;mxn<<=1);
    	prepare();
    	solve(0,mxn-1);
    	for(int i=0;i<n;i++) printf("%d ",f[i]);puts("");
    	return 0;
    }
    

    当然这个题也可以用生成函数做,设:

    [F(x)=sum_{i=0}^{+infty}f(i)x^i,G(x)=sum_{i=0}^{+infty}g(i)x^i ]

    乘起来:

    [F(x)G(x)=sum_{i=0}^{+infty}x^isum_{j=0}^if(j)g(i-j) ]

    由于(g(0)=0),可以得到:

    [F(x)G(x)=sum_{i=1}^{+infty}f(i)x^i=F(x)-1 ]

    所以:

    [egin{align} F(x)G(x)&equiv F(x)-1 pmod{x^n}\ F(x)&equiv frac{1}{1-G(x)} pmod{x^n}\ end{align} ]

    那么多项式求逆就做完了。

    代码咕咕咕

  • 相关阅读:
    Kubernetes1.91(K8s)安装部署过程(一)--证书安装
    开源仓库Harbor搭建及配置过程
    有关centos7 图形化root用户登录
    linux服务器查看tcp链接shell
    django表格form无法保存评论排查步骤
    Redis 4.x 安装及 发布/订阅实践和数据持久化设置
    django博客项目-设置django为中文语言
    windows 环境下如何使用virtualenv python环境管理工具
    【转载】python中利用smtplib发送邮件的3中方式 普通/ssl/tls
    php安装phpize工具
  • 原文地址:https://www.cnblogs.com/hbyer/p/10551393.html
Copyright © 2011-2022 走看看