• 题解 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;
    }
    
    
    
  • 相关阅读:
    matlab之simulink仿真入门
    20160205.CCPP体系具体解释(0015天)
    logistic回归具体解释(二):损失函数(cost function)具体解释
    Java 垃圾回收之垃圾回收算法
    synchronized
    如何中断线程
    yield函数
    Linux
    notify和notifyAll的区别
    Sleep和Wait的区别
  • 原文地址:https://www.cnblogs.com/colazcy/p/13417166.html
Copyright © 2020-2023  润新知