快速阶乘算法(暂无实践)

Problem

模板题luogu5282

  • 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 n log2n

  • 一种暴力 的方法是多项式加分块,设定一个块的大小 B B B,以及这样一个多项式:
    f ( x ) = ∏ i = 1 B ( x + i ) f(x)=\prod_{i=1}^B{(x+i)} f(x)=i=1B(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/BB)B
  • 直接利用多项式多点求值可以搞到 n l o g 2 n \sqrt{n}log^2n n log2n的复杂度。

n l o g n \sqrt{n}logn n logn

  • 直接求系数实在是太慢了,我们可以考虑另一种多项式的优秀处理方法——点值。
  • 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=0dh(i)j=iijΔ+nj
    = ∏ 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=0d(Δ+nj)i=0di!(ni)!h(i)(1)niΔ+ni1
  • 由于 d < = B d<=B d<=B,所以不会出现 Δ + n − j = i \Delta+n-j=i Δ+nj=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)

你可能感兴趣的:(学习小计,FFT和NTT,多项式,分块,fft,倍增)