luoguP4721 【模板】分治 FFT

P4721 【模板】分治 FFT

链接

luogu

题目描述

给定长度为 \(n-1\) 的数组 \(g[1],g[2],..,g[n-1]\),求 \(f[0],f[1],..,f[n-1]\),其中
\[f[i]=\sum_{j=1}^if[i-j]g[j]\]
边界为 \(f[0]=1\) 。答案模 \(998244353\)

思路

分治+ntt。跑900+ms
其实limit只要设到区间长度就可以了,其他的是用不到的。对前半部分也没得影响。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=4e5+7,mod=998244353;
int read() {
    int x=0,f=1;char s=getchar();
    for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
    return x*f;
}
int n,len_a,len_b,p,limit;
int f[N],g[N],a[N],b[N],r[N];
int q_pow(int a,int b) {
    int ans=1;
    while(b) {
        if(b&1) ans=1LL*ans*a%mod;
        a=1LL*a*a%mod;
        b>>=1;
    }
    return ans;
}
void ntt(int *a,int type) {
    for(int i=0;i<=limit;++i)
        if(i<r[i]) swap(a[i],a[r[i]]);
    for(int mid=1;mid<limit;mid<<=1) {
        int Wn=q_pow(3,(mod-1)/(mid<<1));
        for(int i=0;i<limit;i+=(mid<<1)) {
            for(int j=0,w=1;j<mid;++j,w=1LL*w*Wn%mod) {
                int x=a[i+j],y=1LL*w*a[i+j+mid]%mod;
                a[i+j]=(x+y)%mod;
                a[i+j+mid]=(x-y+mod)%mod;
            }
        }
    }
    if(type==-1) {
        reverse(&a[1],&a[limit]);
        int inv=q_pow(limit,mod-2);
        for(int i=0;i<=limit;++i) a[i]=1LL*a[i]*inv%mod;
    }
}
void init() {
    limit=1,p=0;
    while(limit<len_b) limit<<=1,p++;
    for(int i=len_a;i<=limit;++i) a[i]=0;
    for(int i=len_b;i<=limit;++i) b[i]=0;
    for(int i=0;i<=limit;++i)
        r[i]=(r[i>>1]>>1)|((i&1)<<(p-1));
}
void solve(int l,int r) {
    if(l>=r) return;
    int mid=(l+r)>>1;
    solve(l,mid);
    len_a=0,len_b=0;
    for(int i=l;i<=mid;++i) a[len_a++]=f[i];
    for(int i=1;i<=r-l;++i) b[len_b++]=g[i];
    init();
    ntt(a,1),ntt(b,1);
    for(int i=0;i<=limit;++i) a[i]=1LL*a[i]*b[i]%mod;
    ntt(a,-1);
    for(int i=mid+1;i<=r;++i) f[i]=(f[i]+a[i-l-1])%mod;
    solve(mid+1,r);
}
int main() {
    n=read();
    for(int i=1;i<n;++i) g[i]=read();
    f[0]=1;
    solve(0,n-1);
    for(int i=0;i<n;++i) printf("%d ",f[i]);
    return 0;
}
全部评论

相关推荐

小红书 后端选手 n*16*1.18+签字费期权
点赞 评论 收藏
分享
头像
11-06 10:58
已编辑
门头沟学院 嵌入式工程师
双非25想找富婆不想打工:哦,这该死的伦敦腔,我敢打赌,你简直是个天才,如果我有offer的话,我一定用offer狠狠的打在你的脸上
点赞 评论 收藏
分享
10-07 20:48
门头沟学院 Java
听说改名就会有offer:可能是实习上着班想到后面还要回学校给导师做牛马,看着身边都是21-25的年纪,突然emo了了
点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务