分治fft是非常明显的做法,不过这样是$\mathcal O(n\log^2n)$的. 把生成函数弄出来之后会发现它是个微分方程,可以有一些神奇的方法来解,具体可以看UR3的题解.
我比较菜所以还是决定写分治+卡常,发现了一个卡常技巧. 对$[l,r)$区间分治的时候,设$m=\left\lfloor\frac{l+r}{2}\right\rfloor$,如果$l\neq0$,就要把$C(z)$,$F(z)$在$[l,m)$的部分,$F(z)$在$[0,r-l)$的部分卷起来,这里fft的长度看似要开到$4(r-l)$,但事实上只需要开到$2(r-l)$,因为超出$2(r-l)$的部分小于$2(r-l)+(m-l)$,这样就算循环到前面去,也会小于$m-l$,而对$[m,r)$的贡献是从$m-l$开始的,所以不影响答案. 而$l=0$的时候fft长度显然也可以只开到$2(r-l)$. 这样一来可以显著减小常数. 跑得比网上搜到的倍增还快!
另外以后在我学会倍增解微分方程之前,看到微分方程不会解可以考虑分治.
代码:
1 |
|