分治FFT

分治FFT

例题传送门

solution-1:多项式求逆

我们考虑构造函数 \(f(x)=\sum_{i=0}^\infty f[i]x^i,\ g(x)=\sum_{i=0}^\infty g[i]x^i\)

\(f(x)\) 就是目标函数,\(g(x)\) 就是题目给出的函数,但这里我们令 \(g[0]=0\)

将它们卷起来:

\[f(x)*g(x)=\sum_{k=0}^\infty x^k\sum_{i=0}^k f[k-i]g[i] \]

\(k=0\) 时,有 \(\sum_{i=0}^k f[k-i]g[i]=0\)

\(k\not = 0\) 时,有 \(\sum_{i=0}^k f[k-i]g[i]=\sum_{i=1}^k f[k-i]g[k]=f[k]\)

也就是有:

\[f(x)*g(x)=f(x)-f[0] \]

又因为 \(f[0]=1\)

所以我们能够得到:

\[f(x)=\frac{1}{1-g(x)} \]

求逆即可

代码

solution-2:分治FFT

这才是我们今天的主角

这其实是 cdq分治 的思想

我们不难发现,其实我们可以将贡献单独拆出来

每次我们枚举到 \([l,r]\) 区间时,我们先递归左区间求出 \([l,mid]\),然后将左区间贡献到右区间,最后再递归右区间

借鉴 command_block博客,我们令 F=<0, 1, 3, 2>,要求的是 G=<1,0,0,0> (初始值)

下面是模拟过程:([] 表示分治的区间,| 表示左右区间的分隔)

递归到 G=<[1| 0], 0, 0>,我们让 [1,0] 卷上 F<0, 1>,得到 <*, 1>,其中 * 表示我们不需要关心的位置

回到 G=<[1, 1| 0, 0]>,让 [1, 1| 0, 0] 卷上 F<0, 1, 3, 2>,得到 <*, *, 4, 5>

递归到 G=<1, 1, [4| 5]>,让 [4, 5] 卷上 F<0, 1>, 得到 <*, 4>,并G 对应的位置

注意:这里并不是与 F 的后半部分 <3, 2> 进行卷积

最后就得到 G=<1, 1, 4, 9>

时间复杂度是 \(O(n\log^2 n)\)

其实可以发现,我们在 cdq 时一直只用到了 F点值形式,因此我们可以考虑预处理出它某一段的点值来加速

真正进行 cdq 时可以将区间长度扩充成 \(2\) 的整次幂

代码(确实比求逆慢了不少)

posted @ 2022-04-25 21:47  zuytong  阅读(37)  评论(0编辑  收藏  举报