日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[组合数]求组合数的几种方法总结

發布時間:2025/3/21 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [组合数]求组合数的几种方法总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

求C(n,m)%mod的方法總結

1.當n,m都非常小的時候能夠利用楊輝三角直接求。
C(n,m)=C(n-1,m)+C(n-1,m-1)。

2.利用乘法逆元。
乘法逆元:(a/b)%mod=a*(b^(mod-2)) mod為素數。
逆元能夠利用擴展歐幾里德或歐拉函數求得:

1).擴展歐幾里德:b*x+p*y=1 有解,x就是所求2).費馬小定理:b^(p-1)=1(mod p),故b*b^(p-2)=1(mod p),所以x=b^(p-2)

1. n!/(m!*(n-m)! =x%p ,先對算出n!、m!

、(n-m)!對p取模的余數。就轉換為a/b=x%p;由于p為素數。所以等價于bx+py=a;然后用擴展的歐幾里得定理算出 bx’+py’=1的解。x=x’*a,就得到了終于的x的值,即C(m,n)%p得值。

2.逆元 事實上假設mod是素數 則b的逆元事實上就是b^(mod-2)
也就是 (m!(n-m)!)的逆元為 (m!(n-m)!)p-2 ;

int inv(int a) { //return fpow(a, MOD-2, MOD); return a == 1 ?

1 : (long long)(MOD - MOD / a) * inv(MOD % a) % MOD; } LL C(LL n,LL m) { if(m < 0)return 0; if(n < m)return 0; if(m > n-m) m = n-m; LL up = 1, down = 1; for(LL i = 0 ; i < m ; i ++){ up = up * (n-i) % MOD; down = down * (i+1) % MOD; } return up * inv(down) % MOD; }

3.當n和m比較大,mod是素數且比較小的時候(10^5左右)。通過Lucas定理計算

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)

#include<iostream> //#include<algorithm> using namespace std; typedef long long ll; int quick_power_mod(int a,int b,int m){//pow(a,b)%mint result = 1;int base = a;while(b>0){if(b & 1==1){result = (result*base) % m;}base = (base*base) %m;b>>=1;}return result; } //計算組合數取模 ll comp(ll a, ll b, int p) {//composite num C(a,b)%pif(a < b) return 0;if(a == b) return 1;if(b > a - b) b = a - b;int ans = 1, ca = 1, cb = 1;for(ll i = 0; i < b; ++i) {ca = (ca * (a - i))%p;cb = (cb * (b - i))%p;}ans = (ca*quick_power_mod(cb, p - 2, p)) % p;return ans; } ll lucas(ll n, ll m, ll p) {ll ans = 1;while(n&&m&&ans) {ans = (ans*comp(n%p, m%p, p)) % p;//also can be recusiven /= p;m /= p;}return ans; } int main(){ll m,n;while(cin>>n>>m){cout<<lucas(n,m,10007)<<endl;}return 0; }

C(n % mod, m % mod) % mod; 假設太大還是利用上面的逆元來處理。

半預處理
由于Lucas定理保證了階乘的數均小于p,所以能夠講全部的階乘先預處理,優化C(n,m)
mod的要求:p<10^6,且為素數
有效范圍:1<=n,m<=10^9

//半預處理 const ll MAXN = 100000; ll fac[MAXN+100]; void init(int mod) { fac[0] = 1; for (int i=1; i<mod; i++){ fac[i] = fac[i-1] * i % mod; } } //半預處理逆元求C(n。m)%mod ll C(ll n, ll m) { if ( m>n ) return 0; return fac[n] * (GetInverse(fac[m]*fac[n-m], mod)) % mod; }

4.另一種就是分解質因子。這個比較麻煩。
http://www.mamicode.com/info-detail-621758.html

總結

以上是生活随笔為你收集整理的[组合数]求组合数的几种方法总结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。