Problem
- 求 n ! m o d p n!\ mod\ p n! mod p, p p p是质数
- 由于是任意模数,所以需要MTT。
n l o g 2 n \sqrt{n}log^2n nlog2n
- 一种
暴力的方法是多项式加分块,设定一个块的大小 B B B,以及这样一个多项式:
f ( x ) = ∏ i = 1 B ( x + i ) f(x)=\prod_{i=1}^B{(x+i)} f(x)=i=1∏B(x+i) - 那么答案就是 f ( 0 ) ∗ f ( B ) ∗ f ( 2 B ) ∗ . . . ∗ f ( n / B ∗ B ) ∗ 最 后 剩 下 不 超 过 B 的 部 分 的 乘 积 f(0)*f(B)*f(2B)*...*f(n/B*B)*最后剩下不超过B的部分的乘积 f(0)∗f(B)∗f(2B)∗...∗f(n/B∗B)∗最后剩下不超过B的部分的乘积
- 直接利用多项式多点求值可以搞到 n l o g 2 n \sqrt{n}log^2n nlog2n的复杂度。
n l o g n \sqrt{n}logn nlogn
- 直接求系数实在是太慢了,我们可以考虑另一种多项式的优秀处理方法——点值。
- 设 f d ( x ) = ∏ i = 1 d ( x + i ) f_d(x)=\prod_{i=1}^d(x+i) fd(x)=∏i=1d(x+i),那么我们最后就是要求所有的 f B ( i B ) f_B(iB) fB(iB)
- 利用倍增的思路,如果我们可以做到从 f d ( 0 , B . . d B ) f_d(0,B..dB) fd(0,B..dB)到 f 2 d ( 0 , B . . 2 d B ) f_{2d}(0,B..2dB) f2d(0,B..2dB)的乘二的转化,以及加一的转化,那么就可以倍增求出最后的 B B B个点值了
乘二
- 对于 f d ( 0 , B . . . d B ) f_d(0,B...dB) fd(0,B...dB),首先需要变成 f d ( 0 , B . . . 2 d B ) f_d(0,B...2dB) fd(0,B...2dB).
- 然后再在对应位置上乘上 f d ( d , d + B . . . , d + 2 d B ) f_d(d,d+B...,d+2dB) fd(d,d+B...,d+2dB),就可以变成 f 2 d ( 0 , B . . . 2 d B ) f_{2d}(0,B...2dB) f2d(0,B...2dB)
- 考虑第一步需要得到 f d ( d B . . . 2 d B ) f_d(dB...2dB) fd(dB...2dB),再综合第二步,都相当于是从 f d ( i B ) f_d(iB) fd(iB)变成 f d ( i B + x ) f_d(iB+x) fd(iB+x)
- 系统化得来说,假设 h ( i ) = f d ( i B ) h(i)=f_d(iB) h(i)=fd(iB),那么相当于我们已知 h ( 0.. d ) h(0..d) h(0..d),要求 h ( 0 + x / B , 1 + x / B . . d + x / B ) h(0+x/B,1+x/B..d+x/B) h(0+x/B,1+x/B..d+x/B)。
- 运用拉格朗日插值:
h ( Δ + n ) = ∑ i = 0 d h ( i ) ∏ j ≠ i Δ + n − j i − j h(\Delta +n)=\sum_{i=0}^dh(i)\prod_{j\neq i}\frac{\Delta+n-j}{i-j} h(Δ+n)=i=0∑dh(i)j=i∏i−jΔ+n−j
= ∏ j = 0 d ( Δ + n − j ) ∑ i = 0 d h ( i ) ∗ ( − 1 ) n − i i ! ( n − i ) ! ∗ 1 Δ + n − i =\prod_{j=0}^d(\Delta+n-j)\sum_{i=0}^d\frac{h(i)*(-1)^{n-i}}{i!(n-i)!}*\frac{1}{\Delta+n-i} =j=0∏d(Δ+n−j)i=0∑di!(n−i)!h(i)∗(−1)n−i∗Δ+n−i1 - 由于 d < = B d<=B d<=B,所以不会出现 Δ + n − j = i \Delta+n-j=i Δ+n−j=i的情况。后面可以直接FFT,前面的只需要用双指针扫一遍即可。
加一
- 从 f d ( 0 , B . . d B ) f_d(0,B..dB) fd(0,B..dB)到 f d + 1 ( 0 , B . . d B , ( d + 1 ) B ) f_{d+1}(0,B..dB,(d+1)B) fd+1(0,B..dB,(d+1)B)直接暴力即可。
时间复杂度
- T ( n ) = T ( n / 2 ) + n l o g n = O ( n l o g n ) T(n)=T(n/2)+n\ log \ n=O(n\ log \ n) T(n)=T(n/2)+n log n=O(n log n)