1. 程式人生 > >Lucas 大組合數

Lucas 大組合數

.com 技術 利用 費馬小定理 題目 image 證明 max i++

題目:HDU 3037

題意:有n個樹,m個堅果,放到n個樹裏,可以不放完,有多少種方法。

分析:

技術分享

得到組合數了。

大組合數什麽費馬小定理,Lucas定理都來了;

總的說,不能用二維地推了,用的卻是組合數的定義。

技術分享

一般來說大組合通常要取模。

那麽不能邊乘邊模,邊除邊模,等式不會成立。

根據逆元,除以一個數取模 = 乘以這個數對mod的逆元。

那麽式子就可以寫成:技術分享

這裏,我們可以預處理所有 i 對 mod 的逆元後,累乘,這樣得到的就是階乘的逆元。

然後就是求 i 對 mod 的逆元了,什麽擴展歐幾裏得就來了。

當然,有費馬小定理。

inv[i] = (mod-mod/i)*inv[mod%i]%mod;

整個求大組合數就是這樣出來了。

void init() {

    fac[0] = 1;
    for(int i=1;i<maxn;i++)
        fac[i] = i*fac[i-1]%mod;

    inv[0] = inv[1] = 1;
    for(int i=2;i<maxn;i++)
        inv[i] = (ll)(mod-mod/i)*inv[mod%i]%mod;

    for(int i=2;i<maxn;i++)
        inv[i] = inv[i-1]*inv[i]%mod;

}

ll C(ll n,ll m) {

    
if(n<m) return 0; return fac[n]*inv[m]%mod*inv[n-m]%mod; }

但是這個題目n,m的範圍驚人1000000000,作為階乘,逆元,數組開不下。

Lucas來了:

技術分享

看結果吧:

技術分享

還是有組合數,用了費馬定理:

fac[n]*Inv(fac[m])%P*Inv(fac[n-m])%P;

因為這裏的對P的逆元 Inv已經不能用數組表示和地推了,Inv()函數,利用了費馬定理,快速冪等等,原理很復雜了,哈哈~~~,我就不證明了。

void initFac(int n) {
    fac[
0] = 1; for(int i=1;i<=n;i++) fac[i] = i*fac[i-1]%P; } ll Pow(ll a,int b) { ll re = 1; for(;b;b>>=1,a=a*a%P) if(b&1) re = re*a%P; return re; } ll Inv(ll a) { return Pow(a,P-2); } ll C(ll n,ll m) { if(n<m) return 0; return fac[n]*Inv(fac[m])%P*Inv(fac[n-m])%P; } ll Lucas(ll n,ll m) { if(n<m) return 0; ll re = 1; for(;m;n/=P,m/=P) re = re*C(n%P,m%P)%P; return re; }

Lucas 大組合數