题解 P4721 【【模板】分治 FFT】

题目链接

Solution 【模板】分治 FFT

题目大意:给定(g_{1ldots n-1},f_0=1),求(f_{1 ldots n-1}),其中(f_i=sum_{j=1}^{i}f_{i-j}g_j),对(998244353)取模

NTT、分治


分析:

有两种做法:首先可以多项式求逆(现在还不会

然后可以用分治加上NTT(FFT)优化卷积的方法

首先我们注意到,对于一个位置(i),它依赖于([0,i-1])(f)的值,如果依次计算的话时间复杂度无法承受

这个时候可以用分治,计算一段区间内的(f)值对于另一段区间的贡献

类似于(cdq)分治,我们计算完左区间后,考虑左区间会对右区间产生多少贡献。这个直接将左区间的(f)(g)做一个卷积就可以了

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 3e5 + 100,mod = 998244353;
// g = 3,inv = 332748118
namespace Fast_IO{
    const int bufsiz = 1 << 20;
    char buf[bufsiz],*ed = buf + bufsiz,*p = buf;
    inline char getch(){
        #ifndef ONLINE_JUDGE
            return getchar();
        #endif
        if(p == ed){
            fread(buf,sizeof(char),bufsiz,stdin);
            p = buf;
        }
        return *(p++);
    }
    inline int read(){
        int x = 0;char c = getch();
        while(!isdigit(c))c = getch();
        while(isdigit(c))x = x * 10 + c - '0',c = getch();
        return x;
    }
}using Fast_IO::read;
inline int add(int a,int b){return (a + b) % mod;}
inline int sub(int a,int b){return ((a - b) % mod + mod) % mod;}
inline int mul(int a,int b){return (1ll * a * b) % mod;}
inline int qpow(int a,int b){
    int res = 1,base = a;
    while(b){
        if(b & 1)res = mul(res,base);
        base = mul(base,base);
        b >>= 1;
    }
    return res;
}
inline int inv(int x){return qpow(x,mod - 2);}
int n,N,tr[maxn << 1],g[maxn << 1],f[maxn << 1],tmp1[maxn << 1],tmp2[maxn << 1];
inline void ntt(int f[],int N,int flag){
    for(int i = 0;i < N;i++)
        if(i < tr[i])swap(f[i],f[tr[i]]);
    for(int p = 2;p <= N;p <<= 1){
        int len = p >> 1,unit = qpow(flag == 1 ? 3 : 332748118,(mod - 1) / p);
        for(int k = 0;k < N;k += p){
            int g = 1;
            for(int l = k;l < k + len;l++){
                int tt = mul(f[l + len],g);
                f[l + len] = sub(f[l],tt);
                f[l] = add(f[l],tt);
                g = mul(g,unit);
            }
        }
    }
}
inline void cdq(int a,int b){
    if(a == b)return;
    int mid = (a + b) >> 1;
    cdq(a,mid);
    int N = (b - a + 1) << 1;
    for(int i = 0;i < N;i++)
        tr[i] = (tr[i >> 1] >> 1) | ((i & 1) ? (N >> 1) : 0);
    for(int i = a;i <= mid;i++)tmp1[i - a] = f[i];
    ntt(tmp1,N,1);
    for(int i = 1;i <= b - a;i++)tmp2[i] = g[i];
    ntt(tmp2,N,1);
    for(int i = 0;i < N;i++)tmp1[i] = mul(tmp1[i],tmp2[i]);
    ntt(tmp1,N,-1);
    const int iv = inv(N);
    for(int i = mid + 1;i <= b;i++)
        f[i] = add(f[i],mul(tmp1[i - a],iv));
    for(int i = 0;i < N;i++)tmp1[i] = tmp2[i] = 0;
    cdq(mid + 1,b);
}
int main(){
    n = read();
    for(int i = 1;i < n;i++)g[i] = read();
 	for(N = 1;N < n;N <<= 1);
    f[0] = 1;
    cdq(0,N - 1);
    for(int i = 0;i < n;i++)printf("%d ",f[i]);
    return 0;
}


原文地址:https://www.cnblogs.com/colazcy/p/13417166.html