[Luogu P4721] 【模板】分治 FFT

洛谷传送门

题目背景

也可用多项式求逆解决。

题目描述

给定长度为 n 1 的数组 g [ 1 ] , g [ 2 ] , . . , g [ n 1 ] ,求 f [ 0 ] , f [ 1 ] , . . , f [ n 1 ] ,其中 f [ i ] = j = 1 i f [ i j ] g [ j ]

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

输入输出格式

输入格式:

第一行一个正整数 n

第二行共 n 1 个非负整数 g [ 1 ] , g [ 2 ] , . . , g [ n 1 ] ,用空格隔开。

输出格式:

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

输入输出样例

输入样例#1:

4
3 1 2

输出样例#1:

1 3 10 35

输入样例#2:

10
2 456 32 13524543 998244352 0 1231 634544 51

输出样例#2:

1 2 460 1864 13738095 55389979 617768468 234028967 673827961 708520894

说明

2 n 10 5

0 g [ i ] < 998244353

解题分析

这道题后面的值由一部分前面的贡献得到, 可以使用cdq分治的思想分治计算。 具体而言, 对于一个区间 [ l , r ] , 我们先递归计算 [ l , m i d ] 的答案, 再计算 [ l , m i d ] [ m i d + 1 , r ] 的贡献, 即对应 g [ 1 r l + 1 ] f [ l m i d ] 的卷积, 最后计算 [ m i d + 1 , r ] 的答案。

复杂度 O ( N l o g 2 N )

然而FFT被卡精度了, 只好用NTT代替…

代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <algorithm>
#define ll long long 
#define G 3ll
#define Ginv 332748118ll
#define MOD 998244353ll
#define R register
#define W while
#define IN inline
#define gc getchar()
#define MX 400050
template <class T>
IN void in(T &x)
{
    x = 0; R char c = gc;
    W (!isdigit(c)) c = gc;
    W (isdigit(c))
    x = (x << 1) + (x << 3) + c - 48, c = gc;
}
IN ll fpow(ll now, ll tim)
{
    ll ret = 1;
    for (R unsigned i = 0; i <= 31; ++i, now = now * now % MOD)
    if(tim & (1 << i)) ret = ret * now % MOD;
    return ret;
}
ll a[MX], b[MX], mul[MX], ans[MX];
int len, rev[MX];
IN void NTT(ll *dat, const int &tot, R bool typ)
{
    for (R int i = 0; i < tot; ++i) if(rev[i] < i) std::swap(dat[i], dat[rev[i]]);
    R int now, cur, bd, step, seg;
    ll tar1, tar2, base, deal;
    for (seg = 1; seg < tot; seg <<= 1)
    {
        base = fpow(typ ? G : Ginv, (MOD - 1) / (seg << 1)); step = seg << 1;
        for (now = 0; now < tot; now += step)
        {
            deal = 1, bd = now + seg;
            for (cur = now; cur < bd; ++cur, deal = deal * base % MOD)
            {
                tar1 = dat[cur], tar2 = dat[cur + seg] * deal % MOD;
                dat[cur] = (tar1 + tar2) % MOD; dat[cur + seg] = ((tar1 - tar2) % MOD + MOD) % MOD;
            }
        }
    }
    if(typ) return;
    ll inv = fpow(tot, MOD - 2);
    for (R int i = 0; i < tot; ++i) dat[i] = dat[i] * inv % MOD;
}
void cdq(R int lef, R int rig)
{
    if(lef == rig) return;
    R int bd, tot = 1, lg = 0, siz = rig - lef + 1, mid = lef + rig >> 1;
    cdq(lef, mid);
    bd = siz << 1;
    W (tot <= bd) tot <<= 1, ++lg;
    for (R int i = 0; i < tot; ++i)
    rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1)),
    a[i] = b[i] = 0;
    for (R int i = lef; i <= mid; ++i) a[i - lef] = ans[i];
    for (R int i = 0; i < siz; ++i) b[i] = mul[i];
    NTT(a, tot, 1), NTT(b, tot, 1);
    for (R int i = 0; i < tot; ++i) a[i] = a[i] * b[i] % MOD;
    NTT(a, tot, 0);
    for (R int i = mid + 1; i <= rig; ++i)
    ans[i] = (ans[i] + a[i - lef - 1] % MOD + MOD) % MOD;
    cdq(mid + 1, rig);
}
int main(void)
{
    in(len); --len; ans[0] = 1;
    for (R int i = 0; i < len; ++i) in(mul[i]);
    cdq(0, len);
    for (R int i = 0; i <= len; ++i) printf("%lld ", ans[i]);
}

猜你喜欢

转载自blog.csdn.net/LPA20020220/article/details/81288398