分治 FFT

思想

分治,将左边的贡献加到右边。

具体的,就由递归实现,每次分治的左右区间,在左区间递归求得后,将其贡献给予右区间。

这个 贡献给予,视具体题目而定,就模板题来说,直接卷一下就好了。

一定要注意:分治仅仅是个思想,模板题的作用只是让你知道多项式也是可以和分治结合的,分治 FFT 的应用非常的奇妙。

代码

(觉得不用讲太多,自己调代码调着调着就意会了)

#include <stdio.h>
#include <string.h>
#include <cmath>
using namespace std;
typedef long long LL;
const int N=3e5+3;
const int M=998244353;
const int K=3;

inline int rin()
{
    int s=0;
    bool bj=false;
    char c=getchar();
    for(;(c>'9'||c<'0')&&c!='-';c=getchar());
    if(c=='-')bj=true,c=getchar();
    for(;c>='0'&&c<='9';c=getchar())s=(s<<1)+(s<<3)+(c^'0');
    if(bj)s=-s;
    return s;
}

inline void jh(int &x,int &y){if(x!=y)x^=y^=x^=y;return;}
inline int prpr(int x,int y){return 1LL*x*y%M;}
inline int ksm(int x,int y){int ans=1;for(;y;y>>=1){if(y&1)ans=prpr(ans,x);x=prpr(x,x);}return ans;}

const int Kr=ksm(K,M-2);

int num[N];
int lens;
inline void NTT(int *a,int tag)
{
    for(int i=1;i<lens;i++)if(i>num[i])jh(a[i],a[num[i]]);
    for(int i=1;i<lens;i<<=1)
    {
        int Gyq=ksm(tag?K:Kr,(M-1)/(i<<1));
        for(int j=0;j<lens;j+=(i<<1))
        {
            int Zjj=1;
            for(int k=0;k<i;k++,Zjj=prpr(Zjj,Gyq))
            {
                int x=a[j+k],y=prpr(a[j+k+i],Zjj);
                a[j+k]=(x+y)%M;
                a[j+k+i]=(x-y+M)%M;
            }
        }
    }
    if(!tag)
    {
        int Gyq=ksm(lens,M-2);
        for(int i=0;i<lens;i++)a[i]=prpr(a[i],Gyq);
    }
    return;
}

int n;
int g[N];
int Alpha[N];
int Zeta[N];
int Beta[N];
inline void init(int L,int l,int r,int st)
{
    // memset(Alpha,0,sizeof(Alpha));
    // memset(Zeta,0,sizeof(Zeta));
    int lg=0;
    for(lens=1;lens<L;lens<<=1)lg++;
    for(int i=1;i<lens;i++)num[i]=((num[i>>1]>>1)|((i&1)<<lg-1));
    for(int i=0;i<l;i++)Alpha[i]=g[i];for(int i=l;i<lens;i++)Alpha[i]=0;
    for(int i=0;i<r;i++)Zeta[i]=Beta[i+st];for(int i=r;i<lens;i++)Zeta[i]=0;
    return;
}
inline void dfs_NTT(int *a,int l,int L)
{
    if(L==1){a[0]=(a[0]+g[l])%M;return;}
    int mid=L>>1;
    dfs_NTT(a,l,mid);
    init(L+mid,L,mid,l);
    NTT(Alpha,1);
    NTT(Zeta,1);
    for(int i=0;i<lens;i++)Alpha[i]=prpr(Alpha[i],Zeta[i]);
    NTT(Alpha,0);
    for(int i=mid;i<L;i++)a[i]=(a[i]+Alpha[i-1])%M;
    dfs_NTT(a+mid,l+mid,L-mid);
    return;
}
int main()
{
    int i,j;
    n=rin()-2;
    for(i=0;i<=n;i++)g[i]=rin();
    dfs_NTT(Beta,0,n+1);
    printf("%d ",1);
    for(i=0;i<=n;i++)printf("%d ",(Beta[i]%M+M)%M);printf("\n");
    return 0;
}
上一篇:python – 验证ip-address的JSON Schema无法正常工作


下一篇:实用算法 003:高斯消元算多项式乘法