hdu 3037(lucas定理求大組合數取模)

2021-06-27 03:49:31 字數 1376 閱讀 6975

下面簡單介紹一下lucas定理:

lucas定理是用來求 c(n,m) mod p的值,p是素數(從n取m組合,模上p)。

描述為:

a、b是非負整數,p是質數。ab寫成p進製:a=a[n]a[n-1]...a[0],b=b[n]b[n-1]...b[0]。

則組合數c(a,b)與c(a[n],b[n])*c(a[n-1],b[n-1])*...*c(a[0],b[0])  modp同餘

即:lucas(n,m,p)=c(n%p,m%p)*lucas(n/p,m/p,p) 

lucas(x,0,p)=1;

簡單的理解就是:

以求解n! % p 為例,把n分段,每p個一段,每一段求得結果是一樣的。但是需要單獨處理每一段的末尾p,2p,...,把p提取出來,會發現剩下的數正好又是(n/p)! ,相當於

劃歸了乙個子問題,這樣遞迴求解即可。

這個是單獨處理n!的情況,當然c(n,m)就是n!/(m! *(n-m)!),每乙個階乘都用上面的方法處理的話,就是lucas定理了

lucas最大的資料處理能力是p在10^5左右。

而c(a,b) =a! / ( b! * (a-b)! ) mod p

其實就是求 ( a! / (a-b)!)  * ( b! )^(p-2) mod p

(上面這一步變換是根據費馬小定理:假如p是質數,且a,p互質,那麼a的(p-1)次方除以p的餘數恒為1,

那麼a和a^(p-2)互為乘法逆元,則(b / a) = (b * a^(p-2) ) mod p)

用下面的lucas定理程式實現就能得出結果,實現過程中要注意乘法時的強制轉換

題意:將不大於m顆種子存放在n顆樹中,問有多少種存法。

首先是不大於m顆種子,我沒可以認為少於m的那些種子存放在了第n+1顆樹上,這樣的話,問題就轉化成了將m顆種子存放在n+1顆樹上的方案數。ok這個是組合數學裡面的公式,亦即插板法,也就是x1+x2+x3+……+xn+1 = m;ok,答案是c(n+m,m);

然後就是上面說的lucas定理解決大組合數問題了

#include typedef long long int lld;

using namespace std;

lld pow(lld n,lld m,lld p)//n的m次冪%p

return res;

}lld c(lld n,lld m,lld p)//利用費馬小定理求c(n,m)%p

return a*pow(b,p-2,p)%p;

}lld lucas(lld n,lld m,lld p)//

int main()

{ lld t,m,n,p;

cin>>t;

while(t--)

{cin>>n>>m>>p;

cout<

HDU3037 Lucas定理求大組合數取模

題意 給你三個數,n,m,p,n是樹的個數,m是最多拿的果子,p是最後求的數取模p,問有幾種拿果子的方法。這樣一看這個題就是乙個找規律的題,其實可以把這個題合併起來,樹的個數是n,可以把最多拿的果子看作樹,然後每個樹上拿乙個果子,問這m個果子的拿法。用個辦法來分析這道題目,最終知道這道題其實就是讓你...

hdu 3037 插板法組合 lucas定理

插板法解決的問題 a1 a2 a3 an m 如果a i 必須是正整數,cn 1m 1 如果a i 是非負數,先強制選 1 轉化為正整數cn 1m 1 n擴充套件,對於每個數最小為多少都可以通過先強行加減的方法把它轉化為,正整數問題。lucas定理 解決cm n mo d 的計算。本題就是插板法列出...

HDU 3037 隔板法 組合數 Lucas

題意 求在n棵樹上摘不超過m顆豆子的方案數,結果對p取膜。思路 其實就相當於把i 0 i m 個球放入n個不同的盒子裡,盒子可以為空。很明顯,需要用到隔板法。所以對於i個球,方案數為c i n 1,n 1 總方案數為c n 1,n 1 c n,n 1 c n m 1,n 1 然後根據公式c n,m ...