【學習筆記】擴展Lucas定理

0.概述

用於解決組合數取模的問題。請先學習中國剩餘定理,有點作用的。

1.分解

現在我們要求 (nm)modp{n\choose m}\bmod p 的結果,pp 是個小傢伙,n,mn,m 長的很魁梧。

現在我們找到 pp 的質因數分解 p=ipitip=\prod_{i}p_i^{t_i}

我們如果能求出 (nm)modpiti{n\choose m}\bmod p_i^{t_i}

再用中國剩餘定理合成回去即可了!所以下文就只討論對 pk(pP)p^k(p\in\Bbb{P}) 取模的情況。

2.硬算

(nm)=n!m!(nm)!{n\choose m}=\frac{n!}{m!(n-m)!}

我們試着單獨考慮 n!,m!,(nm)!n!,m!,(n-m)!pp 的倍數,就可以求逆元了。用 f(n)=npxmodpkf(n)=\frac{n}{p^x}\bmod p^k 來表示,其中 xx 是滿足 pxnp^x|n 最大的 xx

我們將 n!n! 分成兩部分,一部分是 pp 的倍數,另一部分不是。即 n!=i=1np(ip)i=1,¬(pi)nin!=\prod_{i=1}^{\lfloor\frac{n}{p}\rfloor}(ip)\cdot \prod_{i=1,\neg(p|i)}^{n}i

後面那一部分大有搞頭。畢竟你要對 pkp^k 取模,做乘法之前也可以先行取模。我們根據“除以 pkp^k 的商”進行分類,就可以看出 i=1,¬(pi)ni(i=1,¬(pi)pki)npki=pknpk+1,¬(pi)ni(modpk)\prod_{i=1,\neg(p|i)}^{n}i\equiv\left(\prod_{i=1,\neg(p|i)}^{p^k}i\right)^{\lfloor\frac{n}{p^k}\rfloor}\cdot\prod_{i=p^k\lfloor\frac{n}{p^k}\rfloor+1,\neg(p|i)}^{n}i\pmod{p^k}

然後前面那一坨把 pp 提出來,得到 i=1np(ip)=pnpi=1npi=np!pnp\prod_{i=1}^{\lfloor\frac{n}{p}\rfloor}(ip)=p^{\lfloor\frac{n}{p}\rfloor}\prod_{i=1}^{\lfloor\frac{n}{p}\rfloor}i=\left\lfloor\frac{n}{p}\right\rfloor\large{!}\cdot p^{\lfloor\frac{n}{p}\rfloor}

注意到 np!\lfloor\frac{n}{p}\rfloor! 中可能仍然有 pp 的因數,於是要遞歸處理。總結一下就是

f(n)f(np)(i=1,¬(pi)pki)npki=pknpk+1,¬(pi)ni(modpk)f(n)\equiv f\left(\middle\lfloor\frac{n}{p}\middle\rfloor\right)\cdot\left(\prod_{i=1,\neg(p|i)}^{p^k}i\right)^{\lfloor\frac{n}{p^k}\rfloor}\cdot\prod_{i=p^k\lfloor\frac{n}{p^k}\rfloor+1,\neg(p|i)}^{n}i\pmod{p^k}

複雜度呢?很明顯是遞推式 T(n)=T(np)+O(pk+logn)T(n)=T(\lfloor\frac{n}{p}\rfloor)+\mathcal O(p^k+\log n) 。不妨認爲 logn\log n 是個小於 pkp^k 的值,就有總複雜度 T(n)=O(pklogn)T(n)=\mathcal O(p^k\log n)

顯然,最壞的情況是 O(plogn)\mathcal O(p \log n) 的。中國剩餘定理合併的時間是不用考慮的,很小。

pp 的因數提了出來,pp 的指數是幾呢?衆所周知,maxxZ+,pxnx=i=1+npi\max_{x\in\Z^+,p^x|n}x=\sum_{i=1}^{+\infty}\left\lfloor\frac{n}{p^i}\right\rfloor

然後就完了。可以提一下 k=1k=1 的特殊情況,(nm)(n/pm/p)(nmodpmmodp)(modp),pP{n\choose m}\equiv{n/p\choose m/p}{n\bmod p\choose m\bmod p}\pmod{p},\quad p\in\Bbb{P}

除法是下取整,P\Bbb P 是質數集合。

代碼

不想寫,今天爆零了,ZzZzSySyXjhXjhZxyZxy 等大佬各種 AKAK 虐全場。

想看他們的博客,還用南無鍊銅佛的博客做引子。

while(true) cout << "我好菜啊啊啊啊!" << endl;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章