zoukankan      html  css  js  c++  java
  • 洛谷 P4721 【模板】分治 FFT 解题报告

    P4721 【模板】分治 FFT

    题目背景

    也可用多项式求逆解决。

    题目描述

    给定长度为 (n−1) 的数组 (g[1],g[2],dots,g[n-1]),求 (f[0],f[1],dots,f[n-1]),其中(f[i]=sum_{j=1}^if[i-j]g[j])

    边界为 (f[0]=1) 。答案模 (998244353)

    输入输出格式

    输入格式:

    第一行一个正整数 (n)

    第二行共 (n−1) 个非负整数 (g[1],g[2],dots,g[n-1]),用空格隔开。

    输出格式:

    一行共 (n) 个非负整数,表示 (f[0],f[1],dots,f[n-1])(998244353) 的值。

    说明

    (2leq nleq 10^5)

    (0leq g[i]<998244353)


    其实就是用了一下( ext{CDQ})分治而已,听说比多项式求逆的应用范围要广一些 ,虽然复杂度是(O(nlog^2n))的。

    实现细节

    • 和斜率优化一样先左然后做然后去右边
    • 每次做NTT时注意不要从右半边的(f)取值,那边不是0...

    Code:

    #include <cstdio>
    #include <algorithm>
    #define ll long long
    const int N=(1<<18)+10;
    const ll mod=998244353,G=3,Gi=332748118;
    #define mul(a,b) a*b%mod
    ll qp(ll d,ll k){ll f=1;while(k){if(k&1) f=mul(f,d);d=mul(d,d);k>>=1;}return f;}
    ll f[N],g[N],a[N],b[N];
    int n,len,L,turn[N];
    void NTT(ll *a,int typ)
    {
        for(int i=0;i<len;i++)
            if(i<turn[i])
                std::swap(a[i],a[turn[i]]);
        for(int le=1;le<len;le<<=1)
        {
            ll wn=qp(typ?G:Gi,(mod-1)/(le<<1));
            for(int p=0;p<len;p+=le<<1)
            {
                ll w=1;
                for(int i=p;i<p+le;i++,w=w*wn%mod)
                {
                    ll tmpx=a[i],tmpy=w*a[i+le]%mod;
                    a[i]=(tmpx+tmpy)%mod;
                    a[i+le]=(tmpx-tmpy)%mod;
                }
            }
        }
    }
    void CDQfft(int l,int r)
    {
        if(l==r) {(f[l]+=g[l])%=mod;return;}
        int mid=l+r>>1;
        CDQfft(l,mid);
        int m=r+1-l;
        len=1,L=-1;
        while(len<=m<<1) len<<=1,++L;
        for(int i=0;i<len;i++) a[i]=b[i]=0,turn[i]=turn[i>>1]>>1|(i&1)<<L;
        for(int i=l;i<=mid;i++) a[i+1-l]=f[i];
        for(int i=1;i<=r+1-l;i++) b[i]=g[i];
        NTT(a,1),NTT(b,1);
        for(int i=0;i<len;i++) a[i]=mul(a[i],b[i]);
        NTT(a,0);
        ll inv=qp(len,mod-2);
        for(int i=mid+1;i<=r;i++) (f[i]+=mul(a[i+1-l],inv))%=mod;
        CDQfft(mid+1,r);
    }
    int main()
    {
        scanf("%d",&n);--n;
        for(int i=1;i<=n;i++) scanf("%lld",g+i);
        f[0]=1;
        CDQfft(1,n);
        for(int i=0;i<=n;i++) printf("%lld ",(f[i]+mod)%mod);
        return 0;
    }
    

    2018.12.6

  • 相关阅读:
    redis可编译
    不要用Serverzoo 提供的CloudLinux 的五大原因 Linode 強大VPS 資源為你解密
    linux加载指定目录的so文件
    超级rtmp服务器和屌丝wowza
    标准IO: 文件的打开与关闭函数 fopen & fclose
    《gdb调试之基础篇》
    linux信号Linux下Signal信号太详细了,终于找到了
    【干货】Chrome插件(扩展)开发全攻略
    斯坦福开源无Bug的随机计算图Certigrad
    心跳包:告诉别人,我还活着
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10079353.html
Copyright © 2011-2022 走看看