分治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\)
将它们卷起来:
当 \(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[0]=1\)
所以我们能够得到:
求逆即可
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\) 的整次幂
代码(确实比求逆慢了不少)