组合数求模(续)

0. 写在前面

本文是组合数求模的续篇,是对前一篇文章里第 33 节内容的拓展。在本文中,一些前置讨论将简要带过,如果需要更细致的描述,请参考前文。

本文介绍的是利用 O(pe+elogpn)\mathcal{O}(p e + e \log_p{n})大数乘法计算 ((nm)modpe)({n \choose m} \bmod p^e) 的技巧,其中 pp 是质数,n,m,en, m, e 是非负整数,并且默认 ppee 是小数字,nnmm 是与 pep^e 同阶或比 pep^e 更高阶的大数字。

这里没有将大数运算的底层代价算入复杂度,主要是考虑到具体实现时存在优化,例如可以通过改用 pp 进制存储消除大数取模运算,也可以通过压缩存储进制降低常数

有一定组合数学基础的读者可以先粗略阅读 Andrew Granville 关于组合数模质数幂次的研究综述, 但是笔者不建议细读这篇综述,因为它涉及太多其他方面的介绍,而且由于它的综述性质,很多定理都是直接引用(或略作改动)并不加证明的,这在一定程度上导致这篇综述里出现了很多明显的错误

本文可以看作是关于 Min_25 在前者的研究基础上进行的改进 的一篇翻译文章。(行文风格可能十分不同?)可惜笔者不才,只对 Min_25 的改进做出一些证明和常数优化,并仅对于 pp 较大的情况分析了其他可能的更优做法(详见 3.4 节)。

注:Min_25 似乎在计算操作数时漏掉了 1logp\frac{1}{\log p} 的因子,导致分析结果变大,实际算出的结果应该和本文一致。

author: skywalkert
original article: http://blog.csdn.net/skywalkert/article/details/104681101
last update time : 2020-03-14

1. 预备知识

本节介绍本文需要用到的新增知识及证明,只需要了解做法的读者可以先跳过此节 。(太长不看 )如遇到未知的定义或定理,请参考前一篇文章或留言询问。

1.1 库默尔定理 (Kummer’s theorem)

νp(x)\nu_p(x) 表示最大的非负整数 kk 使得 pkxp^k \mid x,其中 pp 是质数。库默尔定理表明:νp((nm))\nu_p\left({n \choose m}\right) 等于 mm(nm)(n - m)pp 进制下做加法的进位次数。

以下是笔者的证明方法。

  • 对于任意整数 u0u \geq 0, 0v<p0 \leq v < p,显然有 νp((up+v)!)=νp(u!)+u\nu_p((u p + v)!) = \nu_p(u!) + u,故可以得到 νp(n!)=k1npk\nu_p(n!) = \sum_{k \geq 1}{\left\lfloor\frac{n}{p^k}\right\rfloor}
  • 若令 n=i0nipin = \sum_{i \geq 0}{n_i p^i} (0ni<p)(0 \leq n_i < p)nnpp 进制下的表示,且 Sp(n)=i0niS_p(n) = \sum_{i \geq 0}{n_i},那么有 νp(n!)=i0nipi1p1=nSp(n)p1\nu_p(n!) = \sum_{i \geq 0}{n_i \frac{p^i - 1}{p - 1}} = \frac{n - S_p(n)}{p - 1}
  • 对于组合数 (nm){n \choose m},我们可以得到 νp((nm))=νp(n!)νp(m!)νp((nm)!)=Sp(m)+Sp(nm)Sp(n)p1\nu_p\left({n \choose m}\right) = \nu_p(n!) - \nu_p(m!) - \nu_p((n - m)!) = \frac{S_p(m) + S_p(n - m) - S_p(n)}{p - 1}
  • r=nmr = n - m,考虑 mmrrpp 进制下进行加法的过程,令 cic_i 表示该过程中第 ii 位的结果向第 (i+1)(i + 1) 位进位的次数,则有 ni=mi+ri+ci1pcin_i = m_i + r_i + c_{i - 1} - p\,c_i,其中 c1=0c_{-1} = 0。根据定义,我们可以得到 νp((nm))=Sp(m)+Sp(nm)Sp(n)p1=i0ci\nu_p\left({n \choose m}\right) = \frac{S_p(m) + S_p(n - m) - S_p(n)}{p - 1} = \sum_{i \geq 0}{c_i},即库默尔定理。

顺带一提,对于多元组合数 (nm1,m2,,mk){n \choose m_1, m_2, \ldots, m_k},库默尔定理依旧可以得到 νp((nm1,m2,,mk))=1p1(Sp(n)+j=1kSp(mj))=i0ci\nu_p\left({n \choose m_1, m_2, \ldots, m_k}\right) = \frac{1}{p - 1} \left(-S_p(n) + \sum_{j = 1}^{k}{S_p(m_j)}\right) = \sum_{i \geq 0}{c_i},这里的 cic_i 由定义 ni=(j=1kmj)+cj1pcjn_i = \left(\sum_{j = 1}^{k}{m_j}\right) + c_{j - 1} - p\,c_j 得到。

1.2 上升幂 (Rising factorial) 与无符号第一类斯特林数 (Unsigned stirling numbers of the first kind)

定义关于 xxnn 阶上升幂为 xn=i=0n1(x+i)x^{\overline{n}} = \prod_{i = 0}^{n - 1}{(x + i)},显然这是一个 nn 次多项式,故可以定义 xn=k=0ncoeffn,kxkx^{\overline{n}} = \sum _{k = 0}^{n}{\mathrm{coeff}_{n, k} x^k}

xn+1=xn(x+n)x^{\overline{n + 1}} = x^{\overline{n}} (x + n) 可以得到 coeffn+1,k=coeffn,k1+ncoeffn,k\mathrm{coeff}_{n + 1, k} = \mathrm{coeff}_{n, k - 1} + n\,\mathrm{coeff}_{n, k},而初始情况为 coeff0,0=1\mathrm{coeff}_{0, 0} = 1, coeff0,k=0\mathrm{coeff}_{0, k} = 0 (k>0)(k > 0)

无符号第一类斯特林数 [nk]{n \brack k} 的定义有两种,一种就是 coeffn,k\mathrm{coeff}_{n, k} 的定义,另外一种定义是大小为 nn 且能恰好划分为 kk 个环的置换数量。根据维基百科的相关词条,笔者认为第一种定义是最先出现的,也即 xn=k=0n[nk]xkx^{\overline{n}} = \sum _{k = 0}^{n}{{n \brack k} x^k} 是最初的定义。

顺带一提,上升幂的系数还有一些特征,例如 [n1]=(n1)!{n \brack 1} = (n - 1)!

再顺带一提,根据上升幂和无符号的系数,读者可以相应地定义下降幂和有符号的系数,但此部分与后文无关,故这里略去。

1.3 威尔逊定理 (Wilson’s theorem) 及其扩展 (Gauss’s generalization)

威尔逊定理主要证明的是:当整数 n>1n > 1 时,nn 是质数当且仅当 (n1)!1(modn)(n - 1)! \equiv -1 \pmod{n} 虽然后文只会使用到其中的一个方向,但是出于科普的考虑,本小节将证明其充要性。

  • nn 能表示成两个不相等且大于 1 的整数之积,即 n=xyn = x y (1<x<y)(1 < x < y),则 x,y<nx, y < n,于是 xy(n1)!x y | (n - 1)!,这意味着 (n1)!0(modn)(n - 1)! \equiv 0 \pmod{n}
  • nn 是一个大于 2 的整数的平方,即 n=x2n = x^2 (x>2)(x > 2),则 2x<x2=n2 x < x^2 = n,于是 2x2(n1)!2 x^2 | (n - 1)!,这意味着 (n1)!0(modn)(n - 1)! \equiv 0 \pmod{n}
  • nn 是一个奇质数,则对于 1u<n1 \leq u < nu2≢1(modn)u^2 \not \equiv 1 \pmod{n} 的整数 uu,总能找到唯一的整数 vv 满足 1v<n1 \leq v < nuv1(modn)u v \equiv 1 \pmod{n},这意味着它们在 ((n1)!modn)((n - 1)! \bmod n) 里能够一一抵消,另外由于模 nn 意义下存在原根(或者说模 nn 意义的缩系是一个循环群),则 u21(modn)u^2 \equiv 1 \pmod{n} 最多只会有两个解,实际上这两个解恰好是 11(n1)(n - 1),故可以得到 (n1)!1(modn)(n - 1)! \equiv -1 \pmod{n}。(顺带一提,对于模意义下非零多项式方程,其解数可以参考拉格朗日定理 (Lagrange’s theorem)。)
  • 剩下两个情况为:若 n=4n = 4,则 (n1)!2≢1(modn)(n - 1)! \equiv 2 \not \equiv -1 \pmod{n};若 n=2n = 2,则 (n1)!11(modn)(n - 1)! \equiv 1 \equiv -1 \pmod{n}

高斯在此基础上进行了扩展,其结论是:当且仅当模 nn 意义下有原根时(即 n=2,4,pe,2pen = 2, 4, p^e, 2 p^e,其中 pp 是奇质数,e>0e > 0 时),1u<n, gcd(u,n)=1u\prod_{1 \leq u < n,\ \gcd(u, n) = 1}{u} 在模 nn 意义下与 1-1 同余,否则该乘积与 11 同余。 原证明略冗长,故这里略去。

顺带一提,若读者对模 nn 意义的缩系有一定了解,知道缩系可以表示成多个循环群的直积,则可以尝试这样进行充要证明:缩系中阶不超过 22 的元素构成的子群可以表示成多个大小为 22 的循环群的直积(设为 kk 个),其中每个直积因子中非单位元的元素会产生 2k12^{k - 1} 次贡献,因此当这样的直积因子有至少两个时,最终乘积必然是单位元(即 11),否则(若不存在至少两个这样的直积因子)此时各直积因子的大小互质,这意味着模 nn 意义下的原根存在。

注:这个证法可以证明更一般性的结论,即任意交换群的所有元素之积要么是单位元,要么存在唯一一个阶为 22 的元素,且所有元素之积等于它。

1.4 伯努利公式 (Bernoulli’s formula)

伯努利公式也即等幂公式,主要是将 i=0n1im\sum_{i = 0}^{n - 1}{i^m} 表示成关于 nn(m+1)(m + 1) 次多项式 Sm(n)=1m+1i=1m+1(m+1i)Bm+1iniS_m(n) = \frac{1}{m + 1}\sum_{i = 1}^{m + 1}{{m + 1 \choose i} B_{m + 1 - i} n^i},其中 BiB_i 是伯努利数列的第 ii 项。

考虑 Sm(n)S_m(n) 看作关于 mm 的数列时对应的指数级生成函数 m0Sm(n)m!xm\sum_{m \geq 0}{\frac{S_m(n)}{m!} x^m},可以得到

m0Sm(n)m!xm=i=0n1m0(ix)mm!=i=0n1exp(ix)=exp(nx)1x/exp(x)1x,\begin{aligned} & \sum_{m \geq 0}{\frac{S_m(n)}{m!} x^m} \\ = & \sum_{i = 0}^{n - 1}{\sum_{m \geq 0}{\frac{(i\,x)^m}{m!}}} \\ = & \sum_{i = 0}^{n - 1}{\exp(i\,x)} \\ = & \frac{\exp(n\,x) - 1}{x} \Big/ \frac{\exp(x) - 1}{x}\text{,} \end{aligned}

其中 exp(nx)1x=m0nm+1(m+1)!xm\frac{\exp(n\,x) - 1}{x} = \sum_{m \geq 0}{\frac{n^{m + 1}}{(m + 1)!} x^m},而 xexp(x)1\frac{x}{\exp(x) - 1} 则是伯努利数的指数型生成函数,即 xexp(x)1=m0Bmm!xm\frac{x}{\exp(x) - 1} = \sum_{m \geq 0}{\frac{B_m}{m!} x^m}

将伯努利数的生成函数代入即可求出 Sm(n)S_m(n) 的公式,也可以由 B0=1B_0 = 1 知道 Sm(n)S_m(n) 是关于 nn(m+1)(m + 1) 次多项式。

注:不使用 exp(x)1\exp(x) - 1 而使用 exp(x)1x\frac{\exp(x) - 1}{x} 作为分母是因为前者常数项为 00,而其作为形式幂级数的乘法逆元是不存在的。

1.5 拉格朗日插值法 (Lagrange interpolation)

对于一个已知次数为 mm 的多项式 F(x)F(x),若已知对于 (xi,yi)(x_i, y_i) (i=0,1,,m)(i = 0, 1, \ldots, m) 满足 F(xi)=yiF(x_i) = y_i,则 F(x)=i=0myii(x)F(x) = \sum_{i = 0}^{m}{y_i \ell_i(x)},其中 i(x)=0jm,jixxjxixj\ell_i(x) = \prod_{0 \leq j \leq m, j \neq i}{\frac{x - x_j}{x_i - x_j}} 是满足 i(xi)=1\ell_i(x_i) = 1i(xj)=0\ell_i(x_j) = 0 (ji)(j \neq i) 的插值基函数。 它的存在性和唯一性是显然的,故这里略去证明。


xi=ix_i = i (i=0,1,,mi = 0, 1, \ldots, m) 时,上述式子可以化简为

F(x)=i=0mF(i)(1)mij=0m(xj)i!(mi)!(xi)=i=0mF(i)(1)mi(xi)(xi1mi).F(x) = \sum_{i = 0}^{m}{F(i) \frac{(-1)^{m - i} \prod_{j = 0}^{m}{(x - j)}}{i! (m - i)! (x - i)}} = \sum_{i = 0}^{m}{F(i) (-1)^{m - i} {x \choose i} {x - i - 1 \choose m - i}}\text{.}

这意味着此时的插值基函数 i(x)\ell_i(x)xx 取整数时必然也是整数,那么即使 F(x)F(x) 的系数不能在模 pep^e 意义下表示(即存在 F(x)F(x) 的某个系数,满足其最简分数表示里分母是 pp 的倍数),只要所有相关的 xxF(x)F(x) 是整数,那么我们就可以在预处理的基础上,使用拉格朗日插值法在 O(m)\mathcal{O}(m) 次大数乘法的时间内求出一个 F(x)F(x)

k!=pdkrkk! = p^{d_k} r_k (dk0,gcd(p,rk)=1)(d_k \geq 0, \gcd(p, r_k) = 1),这里需要预处理 (F(i)modpe)(F(i) \bmod p^e), did_i(ri1modpe)(r_i^{-1} \bmod p^e) (i=0,1,,m)(i = 0, 1, \ldots, m)。此处

  • F(i)F(i) 的计算代价需要根据其定义确定,暂时待定。
  • 计算 did_i 的总代价是 O(νp(m!)+m)=O(m)\mathcal{O}\left(\nu_p(m!) + m \right) = \mathcal{O}(m) 次大数除小数。
  • 若先计算所有 rir_i,再进行一次辗转相除得到 rm1r_m^{-1},然后依次得到所有 ri1r_i^{-1},那么只需要 O(m)\mathcal{O}(m) 次大数乘法和一次求逆的代价。
  • 利用辗转相除法进行一次求逆的代价是 O(elog2p)\mathcal{O}(e \log_2{p}) 次大数乘法和大数除法。

2. 计算方法

经过 Min_25 改进的计算方法已经变得相对来说浅显易懂,适合非数学专业的读者阅读思考。与 Andrew Granville 的方法相比,在此基础上增加的优化技巧也变得相对来说容易接受。

2.1 问题转化

对于整数 u0u \geq 00v<p0 \leq v < p,定义

((up+v)!)p=0xup+v, gcd(x,p)=1x=(i=0u1j=1p1(ip+j))j=1v(up+j),((u\,p + v)!)_p = \prod_{0 \leq x \leq u\,p + v,\ \gcd(x, p) = 1}{x} = \left(\prod_{i = 0}^{u - 1}{\prod_{j = 1}^{p - 1}{(i\,p + j)}}\right) \prod_{j = 1}^{v}{(u\,p + j)}\text{,}

则有

n!=pνp(n!)i0((npi+1p+ni)!)p,n! = p^{\nu_p(n!)} \prod_{i \geq 0}{\left(\left(\left\lfloor\frac{n}{p^{i + 1}}\right\rfloor p + n_i\right)!\right)_p}\text{,}

其中每个 ((up+v)!)p((u\,p + v)!)_p 都是与 pp 互质的值,因此计算 (nm)modpe{n \choose m} \bmod p^e 可以化为计算 O(logpn)\mathcal{O}(\log_p{n})(((up+v)!)pmodpeνp((nm)))\left(((u\,p + v)!)_p \bmod p^{e - \nu_p\left({n \choose m}\right)}\right)、相应次大数乘法,以及一次求逆。对于 νp((nm))e\nu_p\left({n \choose m}\right) \geq e 的情况,可以直接得出 (nm)modpe=0{n \choose m} \bmod p^e = 0


注意到

j=1v(up+j)=(up)v+1up=k=0v[v+1k+1](up)k,\prod_{j = 1}^{v}{(u\,p + j)} = \frac{(u\,p)^{\overline{v + 1}}}{u\,p} = \sum_{k = 0}^{v}{{v + 1 \brack k + 1} (u\,p)^k}\text{,}

((up)kmodpe)((u\,p)^k \bmod p^e)kpk \geq p 时一定为 00,故计算一段连续的与 pp 互质的数之积可以在 O(min{p,e})\mathcal{O}(\min\{p, e\}) 次大数乘法运算内完成。

同样地,我们也可以得到

i=0u1j=1p1(ip+j)i=0u1(k=0min{p,e}1[pk+1](ip)k)(modpe).\prod_{i = 0}^{u - 1}{\prod_{j = 1}^{p - 1}{(i\,p + j)}} \equiv \prod_{i = 0}^{u - 1}{\left(\sum_{k = 0}^{\min\{p, e\} - 1}{{p \brack k + 1} (i\,p)^k}\right)} \pmod{p^e}\text{.}

2.2 优化分析

注意到上一小节末尾的式子是最难计算的部分,暴力计算它需要 O(umin{p,e})\mathcal{O}(u \min\{p, e\}) 次大数乘法和大数加法,而 uu 本身便可以是一个大数字,因此我们需要优化这部分的计算量。


注意到 gcd([p1],p)=gcd((p1)!,p)=1\gcd({p \brack 1}, p) = \gcd((p - 1)!, p) = 1,故 ([p1]1modpe)\left({p \brack 1}^{-1} \bmod{p^e}\right) 存在,则

i=0u1(k=0min{p,e}1[pk+1](ip)k)[p1]ui=0u1(1+k=1min{p,e}1[pk+1][p1](ip)k)(modpe).\prod_{i = 0}^{u - 1}{\left(\sum_{k = 0}^{\min\{p, e\} - 1}{{p \brack k + 1} (i\,p)^k}\right)} \equiv {p \brack 1}^{u} \prod_{i = 0}^{u - 1}{\left(1 + \sum_{k = 1}^{\min\{p, e\} - 1}{\frac{{p \brack k + 1}}{{p \brack 1}} (i\,p)^k}\right)} \pmod{p^e}\text{.}


A(x)=k=1min{p,e}1akxkA(x) = \sum_{k = 1}^{\min\{p, e\} - 1}{a_k x^k},其中 ak=([p1]1[pk+1])modpea_k = \left({p \brack 1}^{-1} {p \brack k + 1}\right) \bmod p^e整数。注意,这里 A(x)A(x) 是定义在有理数域上的多项式,而有理数域上多项式的系数是可以表示成最简分数的有理数,但是分母可能是 pp 的倍数。

考虑形式幂级数 Bu(x)=i=0u1(1+A(ix))B_u(x) = \prod_{i = 0}^{u - 1}{(1 + A(i\,x))},那么有

Bu(x)=i=0u1(1+k=1min{p,e}1akikxk)=1+k1tu,kxk,B_u(x) = \prod_{i = 0}^{u - 1}{\left(1 + \sum_{k = 1}^{\min\{p, e\} - 1}{a_k i^k x^k}\right)} = 1 + \sum_{k \geq 1}{t_{u, k} x^k}\text{,}

这里 tu,kt_{u, k} 一定是整数,因为 akika_k i^k 是整数,这和 xx 的取值范围无关。

注意到我们希望计算的是 (Bu(p)modpe)(B_u(p) \bmod p^e),而当 kek \geq e 时,pepkp^e | p^k(tu,kmodpe)(t_{u, k} \bmod p^e) 一定可以表示出来,那么

Bu(p)1+k=1e1tu,kpk(modpe),B_u(p) \equiv 1 + \sum_{k = 1}^{e - 1}{t_{u, k} p^k} \pmod{p^e}\text{,}

这启发我们寻找 tu,kt_{u, k} 的表达式,从而计算出所求的式子。


C(x)=ln(1+A(x))=k1(1)k1kAk(x)=k1ckxkC(x) = \ln{(1 + A(x))} = \sum_{k \geq 1}{\frac{(-1)^{k - 1}}{k} A^k(x)} = \sum_{k \geq 1}{c_k x^k}(注意 ckc_k有理数,可能不是整数),于是有

lnBu(x)=i=0u1ln(1+A(ix))=i=0u1k1ck(ix)k=k1cksu,kxk,\ln{B_u(x)} = \sum_{i = 0}^{u - 1}{\ln{(1 + A(i\,x))}} = \sum_{i = 0}^{u - 1}{\sum_{k \geq 1}{c_k (i x)^k}} = \sum_{k \geq 1}{c_k s_{u, k} x^k}\text{,}

这里 su,k=i=0u1iks_{u, k} = \sum_{i = 0}^{u - 1}{i^k} 是一个关于 uu(k+1)(k + 1) 次多项式。

Bu(x)=exp(lnBu(x))=exp(lnBu(x))lnBu(x)=Bu(x)lnBu(x)B_u'(x) = \exp'{(\ln{B_u(x)})} = \exp{(\ln{B_u(x)})} \ln'{B_u(x)} = B_u(x) \ln'{B_u(x)}

可知

k1ktu,kxk1=(k1tu,kxk)(k1kcksu,kxk1),\sum_{k \geq 1}{k\,t_{u, k} x^{k - 1}} = \left(\sum_{k \geq 1}{t_{u, k} x^k}\right)\left(\sum_{k \geq 1}{k\,c_k s_{u, k} x^{k - 1}}\right)\text{,}

取其中 xk1x^{k - 1} 的系数可知 tu,k=1ki=1ktu,kiicisu,it_{u, k} = \frac{1}{k} \sum_{i = 1}^{k}{t_{u, k - i} i\,c_i s_{u, i}}


su,ks_{u, k} 是关于 uu 的多项式,我们可以归纳得到 tu,kt_{u, k} 也是关于 uu 的多项式,从而确定 Bu(p)B_u(p) 也是关于 uu 的多项式。

具体来说,令 degu(f)\mathrm{deg}_u(f) 表示多项式 ff 关于 uu 的次数,则 degu(tu,k)=maxi=1k(degu(tu,ki)+degu(su,i))\mathrm{deg}_u(t_{u, k}) = \max_{i = 1}^{k}{(\mathrm{deg}_u(t_{u, k - i}) + \mathrm{deg}_u(s_{u, i}))},于是可以归纳证明 degu(tu,k)=kdegu(su,1)=2k\mathrm{deg}_u(t_{u, k}) = k\,\mathrm{deg}_u(s_{u, 1}) = 2 k,而 degu(1+k=1e1tu,kpk)=maxk=1e1degu(tu,k)=2e2\mathrm{deg}_u(1 + \sum_{k = 1}^{e - 1}{t_{u, k} p^k}) = \max_{k = 1}^{e - 1}{\mathrm{deg}_u(t_{u, k})} = 2 e - 2

虽然这个多项式的系数可能不是整数,但当 uu 取非负整数时,多项式的值都是整数,故可以使用拉格朗日插值法计算一个 Bu(p)B_u(p) 在模 pep^e 意义下的值。


此外,注意到当 upe1u \geq p^{e - 1} 时,Bu(p)B_u(p) 里会出现多个 1x<pe, gcd(x,pe)=1x\prod_{1 \leq x < p^e,\ \gcd(x, p^e) = 1}{x},而根据威尔逊定理的扩展,这个部分在模 pep^e 意义下只会是 ±1\pm 1。不妨记这个值为 δ\delta,那么 Bu(p)δu/pe1Bumodpe1(p)(modpe)B_u(p) \equiv \delta^{\left\lfloor u / p^{e - 1} \right\rfloor} B_{u \bmod p^{e - 1}}(p) \pmod{p^e}。为了便于计算,不妨将这里的 pe1p^{e - 1} 换为 2pe12\,p^{e - 1},则前面的正负号计算可以省去。

将插值法用到的 uu 限制在 [0,2pe1)[0, 2\,p^{e - 1}) 的好处是,计算 νp(ui)\nu_p(u - i) (i=0,1,,2e2)(i = 0, 1, \ldots, 2 e - 2) 的代价可以从 O(logpn+e)\mathcal{O}(\log_p{n} + e) 次大数除小数变成 O(e)\mathcal{O}(e) 次大数除小数。


还有一处需要分析的是计算 [p1]u{p \brack 1}^u,注意到多次计算 ((up+v)!)p((u\,p + v)!)_p 时的这部分是可以合并的。合并之后可以看出,(nm){n \choose m} 中所需计算的部分是 [p1]νp((nm)){p \brack 1}^{\nu_p\left({n \choose m}\right)},其幂次的大小是 O(logpn)\mathcal{O}(\log_p{n}) 的,而且只有当 νp((nm))<e\nu_p\left({n \choose m}\right) < e 时才会产生计算,于是暴力计算即可。

2.3 复杂度计算

最后,我们来算一下大数运算的复杂度,这里略去小数运算是因为后者的复杂度远小于前者的复杂度。

要说明的一点是,我们默认存储的进制是 pp 的幂次,大数对 pep^e 取模可以 O(1)\mathcal{O}(1) 实现,故将一次模乘的代价视为一次大数乘法的代价。(但模意义下求逆可能需要多次大数除法。)如果要考虑大数取模的复杂度,可以直接视所有单次大数乘除和一次大数取模同阶。


本文中所有涉及到的部分可以做如下分析:

  • nnmm 视为同阶,大小均为 O(n)\mathcal{O}(n),而它们转化为 pp 进制的代价是 O(logpn)\mathcal{O}(\log_p{n}) 次大数除小数。
  • 为了高效计算一段连续的与 pp 互质的数之积,需要预处理 [ij]{i \brack j} (i=1,2,,p;j=1,2,,min{i,e})(i = 1, 2, \ldots, p; j = 1, 2, \ldots, \min\{i, e\}),代价是 O(pmin{p,e})\mathcal{O}(p \min\{p, e\}) 次大数乘法和大数加法。
  • 预处理 Bi(p)B_i(p) (i=0,1,,2e2)(i = 0, 1, \ldots, 2 e - 2) 的代价是 O(emin{p,e})\mathcal{O}(e \min\{p, e\}) 次大数乘法和大数加法。
  • 预处理插值系数的代价是 O(e+elog2p)\mathcal{O}(e + e \log_2{p}) 次大数乘法、O(elog2p)\mathcal{O}(e \log_2{p}) 次大数除法和 O(e)\mathcal{O}(e) 次大数除小数。
  • Bu(p)B_u(p) 单次求值的代价是 O(e)\mathcal{O}(e) 次大数加法、大数乘法和大数除小数。
  • 计算 O(logpn)\mathcal{O}(\log_p{n}) 个涉及到的 ((up+v)!)p((u\,p + v)!)_p 需要相应次 Bu(p)B_u(p) 求值,以及额外的 O(logpn)\mathcal{O}(\log_p{n}) 次大数加法和大数乘法。

故总代价为

  • 大数加法、大数除小数:比乘除次数少,故略去;
  • 大数乘法:O(pmin{p,e}+emin{p,e}+e+elog2p+elogpn)=O(pe+elogpn)\mathcal{O}(p \min\{p, e\} + e \min\{p, e\} + e + e \log_2{p} + e \log_p{n}) = \mathcal{O}(p\,e + e \log_p{n})
  • 大数除法:O(elog2p)\mathcal{O}(e \log_2{p}),或者视为常数次求逆操作。

3. 一些改进

本节主要介绍一些可能没什么用或者严重超纲的改进方法,供有兴趣的读者研究思考。(本节基本上是 Min_25 没有讨论的内容。)

3.1 减少预处理

pp 远小于 ee 时,可以省去无符号第一类斯特林数的预处理,但复杂度不变


这一点比较显然,留给读者分类讨论。

3.2 降低多项式次数

pp 很大而导致 Bu(x)B_u(x) 的前 ee 项系数(有理数)的最简分母大多数都与 pp 互质时,模 pep^e 意义下多项式的次数可能降低,虽然也不会降低太多就是了


举例来讲,对于 Bu(p)B_u(p)tu,kpkt_{u, k} p^k 的部分,若 tu,k=i=02kcoeffiuit_{u, k} = \sum_{i = 0}^{2 k}{\mathrm{coeff}_i u^i}coeffi\mathrm{coeff}_i 都能在模 pekp^{e - k} 意义下表示,那么根据欧拉定理 (Euler’s theorem) 的扩展形式,总存在 i0eki_0 \leq e - k,使得对于任意 uuui0+δui0+(δmodφ(pek))(modpek)u^{i_0 + \delta} \equiv u^{i_0 + (\delta \bmod \varphi(p^{e - k}))} \pmod{p^{e - k}},于是 tu,kt_{u, k} 的次数就能直接降低到 min{2k,i0+φ(pek)1}\min\{2 k, i_0 + \varphi(p^{e - k}) - 1\},从而降低整体的次数。

通过上述对局部的分析,我们发现只要系数能在模意义下表示,次数就能降低,甚至 pp 不用太大,例如当 p>ep > e 时,所有的系数一定都能表示出来。

注:笔者对系数能表示的证明有点长,故这里略去,推荐有兴趣的读者先证明 C(x)C(x) 中的 kckk\,c_k 是整数。

顺带一提,我们可以利用差分的技巧,求出 Bu(p)B_u(p) 的多阶差分(显然差分值都是整数),从而确定最优的次数。

注:差分可以得出 Bu(p)k=0degu(Bu(p))coeffk(uk)B_u(p) \equiv \sum_{k = 0}^{\mathrm{deg}_u(B_u(p))}{\mathrm{coeff}_k {u \choose k}},其中 coeffk\mathrm{coeff}_k 是整数。然而,从这个结论中我们只能知道,当 p>2e2p > 2 e - 2tu,kt_{u, k} 一定是整数,若想把这个条件进一步扩大(例如 p>ep > e),读者还是需要思考别的方法。

3.3 优化求逆过程

注意到只有求逆可能需要大数除法,而当 pep^e 很大时,求逆部分还有优化空间,甚至避免大数除法,虽然求逆已经不是主要运算量


注意到求逆本身可以看作是模 pep^e 意义下的方程 f(x)=ax1f(x) = a\,x - 1,当 gcd(a,p)=1\gcd(a, p) = 1 时,f(x)0(modpe)f(x) \equiv 0 \pmod{p^e} 有唯一解系 (a1modpe)(a^{-1} \bmod p^e)

不妨设 f(x)0(modpk)f(x) \equiv 0 \pmod{p^k} 的解是 rkr_k (k=1,2,,e)(k = 1, 2, \ldots, e),我们将 (f(r2k)modp2k)(f(r_{2 k}) \bmod p^{2 k})x=rkx = r_k 处泰勒展开,有

0f(r2k)f(rk)+f(rk)(r2krk)(modp2k),0 \equiv f(r_{2 k}) \equiv f(r_k) + f'(r_k) (r_{2 k} - r_k) \pmod{p^{2 k}}\text{,}

r2krkf(rk)f(rk)(modp2k)r_{2 k} \equiv r_k - \frac{f(r_k)}{f'(r_k)} \pmod{p^{2 k}}

由于 pkf(rk)p^k | f(r_k),则上式中的 1f(rk)\frac{1}{f'(r_k)} 只需要知道在模 pkp^k 意义下的值即可,而 a1rk(modpk)a^{-1} \equiv r_k \pmod{p^k},于是有 r2krk(ark1)rkrk(2ark)(modp2k)r_{2 k} \equiv r_k - (a\,r_k - 1) r_k \equiv r_k (2 - a\,r_k) \pmod{p^{2 k}}

我们可以通过小数字的辗转相除求出 r1r_1,然后通过倍增(或者说牛顿迭代法)得到 rer_e,这样做只需要 O(log2p)\mathcal{O}(\log_2{p}) 次小数字乘除和 O(log2e)\mathcal{O}(\log_2{e}) 次大数乘法,从而避免了大数除法。事实上,如果大数乘法使用快速傅里叶变换 (Fast Fourier transform) 实现,则实际的大数乘法运算量等价于 O(1)\mathcal{O}(1)pep^e 规模的大数乘法。

3.4 卷积加速预处理

pp 远大于 eelogpn\log_p{n} 时,预处理的斯特林数里有很多之后用不上的值,若在使用快速傅里叶变换 (Fast Fourier transform) 实现大数乘法基础上再实现系数为大数的多项式乘法,则复杂度可以进一步优化,如果不是那么难写的话


设模 pep^e 意义下的数字 u=i=0e1uipiu = \sum_{i = 0}^{e - 1}{u_i p^i} (0ui<p0 \leq u_i < p),而模 pep^e 意义下关于 xx 的次数为 degx(F)\mathrm{deg}_x(F) 的多项式 F(x)=i=0degx(F)fixi=i=0degx(F)j=0e1fi,jpjxiF(x) = \sum_{i = 0}^{\mathrm{deg}_x(F)}{f_i x^i} = \sum_{i = 0}^{\mathrm{deg}_x(F)}{\sum_{j = 0}^{e - 1}{f_{i, j} p^j} x^i}

注意到 F(x)F(x) 可以看作是关于 ppxx 的二维多项式,那么只需要(在复数域上)实现小数字 fi,jf_{i, j} 的二维离散傅里叶变换 (Discrete Fourier transform),那么就可以在 O(degx(F)elog2(degx(F)e))\mathcal{O}(\mathrm{deg}_x(F)\,e \log_2{(\mathrm{deg}_x(F)\,e)}) 的时间内完成多项式乘法,这里笔者为了简写,决定将一次乘法的代价视作 O(degx(F)log2(degx(F)))\mathcal{O}(\mathrm{deg}_x(F) \log_2{(\mathrm{deg}_x(F))}) 次大数加法和 O(degx(F))\mathcal{O}(\mathrm{deg}_x(F)) 次大数乘法。

Fv(x)=j=1v(x+j)F_v(x) = \prod_{j = 1}^{v}{(x + j)},则有 F2v(x)=Fv(x)Fv(x+v)F_{2 v}(x) = F_v(x) F_v(x + v),注意到当 v<pv < p 时,xx(x+v)(x + v) 不会同时是 pp 的倍数,于是我们无法从 Fv(x)F_v(x) 的前 ee 项系数得到 F2v(x)F_{2 v}(x) 的前 ee 项系数,我们需要进一步的观察。

不妨设定阈值 α=v\alpha = \left\lfloor\sqrt{v}\right\rfloor,那么有 Fv(x)=(i=0α1Fα(x+αi))j=α2+1v(x+j)F_v(x) = \left(\prod_{i = 0}^{\alpha - 1}{F_{\alpha}(x + \alpha\,i)}\right) \prod_{j = \alpha^2 + 1}^{v}{(x + j)},而求 Fv(x)F_v(x) 在某个 xx 处的点值便可以转化为求 Fα(x)F_{\alpha}(x)α\alphaxx 处的点值。由于这 α\alpha 个位置是等差数列,而且 Fα(x)F_{\alpha}(x) 的次数是 α\alpha,读者不难想到使用拉格朗日插值法快速求解这些点值。

举例来说,假设已知 Fα(αi)F_{\alpha}(\alpha\,i) (i=0,1,,α)(i = 0, 1, \ldots, \alpha),现在要求 Fα(up+αk)F_{\alpha}(u\,p + \alpha\,k) (k=0,1,,α1)(k = 0, 1, \ldots, \alpha - 1),那么有

Fα(up+αk)=i=0αFα(αi)0jα,jiup+αkαjαiαj=(0iα,ik(1)αiFα(αi)i!(αi)! αup+α(ki))(0jαup+α(kj)α)+(1)αkFα(αk)k!(αk)!0jα,jkup+α(kj)α,\begin{aligned} & F_{\alpha}(u\,p + \alpha\,k) \\ = & \sum_{i = 0}^{\alpha}{F_{\alpha}(\alpha\,i) \prod_{0 \leq j \leq \alpha, j \neq i}{\frac{u\,p + \alpha\,k - \alpha\,j}{\alpha\,i - \alpha\,j}}} \\ = & \left(\sum_{0 \leq i \leq \alpha, i \neq k}{\frac{(-1)^{\alpha - i} F_{\alpha}(\alpha\,i)}{i! (\alpha - i)!}\ \frac{\alpha}{u\,p + \alpha (k - i)}}\right) \left(\prod_{0 \leq j \leq \alpha}{\frac{u\,p + \alpha (k - j)}{\alpha}}\right) \\ & + \frac{(-1)^{\alpha - k} F_{\alpha}(\alpha\,k)}{k! (\alpha - k)!} \prod_{0 \leq j \leq \alpha, j \neq k}{\frac{u\,p + \alpha (k - j)}{\alpha}}\text{,} \end{aligned}

这里明显出现了一个卷积式,用多项式乘法加速即可。

注:由于 αv<p\alpha \leq v < p,故上式中的分母都是有逆元的,而且可以沿用求阶乘逆元的方法将上式中所需的求逆操作优化到常数次(甚至总数也是常数次)。

同理,我们可以利用拉格朗日插值法辅助倍增求出 Fα(αi)F_{\alpha}(\alpha\,i) (i=0,1,,α)(i = 0, 1, \ldots, \alpha)。例如,根据 Fd(αi)F_d(\alpha\,i) (i=0,1,,d)(i = 0, 1, \ldots, d),我们可以计算出 Fd(αi+d)F_d(\alpha\,i + d), Fd(α(i+d))F_d(\alpha\,(i + d))Fd(α(i+d)+d)F_d(\alpha\,(i + d) + d),从而得到 F2d(αk)F_{2 d}(\alpha\,k) (k=0,1,,2d)(k = 0, 1, \ldots, 2 d),类似地可以得到 F2d+1F_{2 d + 1} 的点值。(如果对这部分有困惑,可以参考 fjzzq2002 的翻译文章。)

这样做所需的等价大数加法和大数乘法运算量是

Tadd(α)=Tadd(α/2)+O(αlog2α)Tadd(α)=O(αlog2α)Tmul(α)=Tmul(α/2)+O(α)Tmul(α)=O(α).\begin{aligned} T_{add}(\alpha) & = T_{add}(\alpha / 2) + \mathcal{O}(\alpha \log_2{\alpha}) & \Rightarrow & T_{add}(\alpha) = \mathcal{O}(\alpha \log_2{\alpha}) \\ T_{mul}(\alpha) & = T_{mul}(\alpha / 2) + \mathcal{O}(\alpha) & \Rightarrow & T_{mul}(\alpha) = \mathcal{O}(\alpha)\text{.} \end{aligned}

通过这样的改进(使用快速傅里叶变换和倍增法等等),我们可以将整体所需的运算量改进到 O((e+logpn)plog2p)\mathcal{O}((e + \log_p{n}) \sqrt{p} \log_2{p}) 次大数加法、O((e+logpn)p)\mathcal{O}((e + \log_p{n}) \sqrt{p}) 次大数乘法,附加常数次求逆。

注:本小节讨论的内容是基于 pmax{e,logpn}p \geq \max\{e, \log_p{n}\} 分析的,而得到的结果只有在 pp 远大于 eelogpn\log_p{n} 时才比第 2 节中的结果更优。

4. 一些讨论

根据本文得出的结论,((2n1)!!mod2e)((2 n - 1)!! \bmod 2^e) 将会是一个关于 nn 的次数不超过 (2e2)(2 e - 2) 的多项式,同理 (i=1n(2i1)!!mod2e)(\sum_{i = 1}^{n}{(2 i - 1)!!} \bmod 2^e) 将会是关于 nn 的次数不超过 (2e1)(2 e - 1) 的多项式。


待补充

©️2020 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值