快速階乘算法(理論,暫時不會實踐)

Problem

模板題luogu5282

  • n! mod pn!\ mod\ ppp是質數
  • 由於是任意模數,所以需要MTT。

nlog2n\sqrt{n}log^2n

  • 一種暴力 的方法是多項式加分塊,設定一個塊的大小BB,以及這樣一個多項式:
    f(x)=i=1B(x+i)f(x)=\prod_{i=1}^B{(x+i)}
  • 那麼答案就是f(0)f(B)f(2B)...f(n/BB)Bf(0)*f(B)*f(2B)*...*f(n/B*B)*最後剩下不超過B的部分的乘積
  • 直接利用多項式多點求值可以搞到nlog2n\sqrt{n}log^2n的複雜度。

nlogn\sqrt{n}logn

  • 直接求係數實在是太慢了,我們可以考慮另一種多項式的優秀處理方法——點值。
  • fd(x)=i=1d(x+i)f_d(x)=\prod_{i=1}^d(x+i),那麼我們最後就是要求所有的fB(iB)f_B(iB)
  • 利用倍增的思路,如果我們可以做到從fd(0,B..dB)f_d(0,B..dB)f2d(0,B..2dB)f_{2d}(0,B..2dB)的乘二的轉化,以及加一的轉化,那麼就可以倍增求出最後的BB個點值了

乘二

  • 對於fd(0,B...dB)f_d(0,B...dB),首先需要變成fd(0,B...2dB)f_d(0,B...2dB).
  • 然後再在對應位置上乘上fd(d,d+B...,d+2dB)f_d(d,d+B...,d+2dB),就可以變成f2d(0,B...2dB)f_{2d}(0,B...2dB)
  • 考慮第一步需要得到fd(dB...2dB)f_d(dB...2dB),再綜合第二步,都相當於是從fd(iB)f_d(iB)變成fd(iB+x)f_d(iB+x)
  • 系統化得來說,假設h(i)=fd(iB)h(i)=f_d(iB),那麼相當於我們已知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(Δ+n)=i=0dh(i)jiΔ+njijh(\Delta +n)=\sum_{i=0}^dh(i)\prod_{j\neq i}\frac{\Delta+n-j}{i-j}
    =j=0d(Δ+nj)i=0dh(i)(1)nii!(ni)!1Δ+ni=\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}
  • 由於d<=Bd<=B,所以不會出現Δ+nj=i\Delta+n-j=i的情況。後面可以直接FFT,前面的只需要用雙指針掃一遍即可。

加一

  • fd(0,B..dB)f_d(0,B..dB)fd+1(0,B..dB,(d+1)B)f_{d+1}(0,B..dB,(d+1)B)直接暴力即可。

時間複雜度

  • T(n)=T(n/2)+n log n=T(n log n)T(n)=T(n/2)+n\ log \ n=T(n\ log \ n)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章