首先給出lucas(盧卡斯)定理:
有非負整數a、b,和素數p,a、b寫成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]) mod p同餘。 即:
lucas(n,m,p)=c(n%p,m%p)×lucas(n/p,m/p,p) ,特別的,lucas(x,0,p)=1。
其實說白了,lucas定理就是求組合數c(n,m)mod p(p是素數)的值,即(( n! /(n-m)!)/m! )mod p,而我們
又知道(a/b)mod p=a*b^(p-2)mod p(這裡用到了一點逆元和費馬小定理的知識),這樣我們就可以在計算階乘的過程中對p取模,不會造成溢位。(需要注意的是lucas定理處理的p的範圍大致為10^5數量級)
看下面一道題:hdu3037
題目大意:m個種子要放在n顆樹上,問有多少種方法,結果對素數p取模。
分析:m個種子可以分成兩部分:放在樹上的和不放在樹上的,我們可以假想出第n+1顆樹,認為那些沒放在樹上的種子放在這顆假想樹上,這樣,問題就變為了m個種子放在n顆樹上有多少種方案數了。等價於方程x1+x2+...+xn+1=m有多少組非負整數解,即(x1+1)+(x2+1)+...+(xn+1+1)=m+n+1有多少組正整數解。擋板原理:(m+n+1)個1,分成n+1部分的方案數==>c(n+m,n)。到這兒就很明顯了,果斷lucas。
實現**如下:
#include #include #include using namespace std;
typedef long long llg;
const int n =150000;
llg n, m, p, fac[n];
void init()
llg quick_mod(llg a, llg b)
return ans;
}llg c(llg n, llg m)
llg lucas(llg n, llg m)
int main()
return 0;
}
對於p比較大的情況,不能對階乘預先處理,需要單獨處理。
題目大意:求c(n,m)mod p。n,p是10^9數量級的。
實現**如下:
#include #include #include using namespace std;
typedef long long ll;
ll n,m,p;
ll quick_mod(ll a, ll b)
b >>= 1;
a = a * a % p;
}return ans;
}ll c(ll n, ll m)
return ans;
}ll lucas(ll n, ll m)
int main()
return 0;
}
Lucas 大組合數
題目 hdu 3037 題意 有n個樹,m個堅果,放到n個樹裡,可以不放完,有多少種方法。分析 得到組合數了。大組合數什麼費馬小定理,lucas定理都來了 總的說,不能用二維地推了,用的卻是組合數的定義。一般來說大組合通常要取模。那麼不能邊乘邊模,邊除邊模,等式不會成立。根據逆元,除以乙個數取模 乘...
Lucas定理 組合數取模
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 然而如果...
stone 組合數學 Lucas定理
傳送門解題思路 第i組的人數必須大於ci,於是我們可以將問題轉化為 n sum m ci 人分到m組中,且保證每一組的人數大於0,然後我們可以使用隔板法求出分的的組數 c m ci 我們可以直接通過基本的組合公式 費馬小定理直接求,也可以通過lucas定理求得 直接求 code includeusi...