盧卡斯(\(Lucas\))定理用於求當\(n\)、\(m\)較大時,\(C_n^m mod\;p(p爲質數)\)的值。spa
對於
\[ n,m \in \mathbb{Z},p爲質數 \]
有
\[ C_n^m mod\;p=C_{n\;mod\;p}^{m\;mod\;p}\cdot C_{n/p}^{m/p} mod\;p \]code
對於
\[ n,m \in \mathbb{Z},p爲質數\\ 設m=\prod_{i=0}^{k}m_ip^i,n=\prod_{i=0}^{k}n_ip^i \]
有
\[ C_n^m mod\;p=\prod_{i=0}^{k}C_{n_i}^{m_i}mod\;p \]遞歸
對於比較大的組合數,咱們先利用盧卡斯定理將其拆分,拆分所獲得的每一個較小的組合數則能夠用更簡單的方法求解。對於遞歸形式,拆分出的\(C_{n\;mod\;p}^{m\;mod\;p}\)還原成階乘形式後,因爲\(p\)爲質數且除數與\(p\)互質,咱們能夠考慮運用費馬小定理之類的方法求逆元進行計算。對於非遞歸形式,至關於把\(m\)、\(n\)均當作一個\(p\)進制下的數,其每一位也與\(p\)互質,也能夠如此計算。ip
注意邊界條件:當\(m=0\)時,\(C_n^m=1\);當\(n<m\)時,\(C_n^m=0\)。階乘能夠進行預處理減小重複計算。class
//遞歸 int power(int b,int k) { int base=1; while(k) { if(k&1) base=(long long)base*b%p; k>>=1; b=(long long)b*b%p; } return base; } int inv(int x) { return power(x,p-2); } int C(int x,int y) { return (long long)factorial[x]*inv((long long)factorial[y]*factorial[x-y]%p)%p; } int Lucas(int x,int y) { if(!y) return 1; if(x%p<y%p) return 0; return C(x%p,y%p)*Lucas(x/p,y/p)%p; }
//非遞歸 int Lucas(int x,int y) { int result=1; while(x&&y) { if(x%p<y%p) return 0; result=(long long)result*C(x%p,y%p)%p; x/=p; y/=p; } return result; }