用普通的組合公式來算
當求c(n,m)%mod時容易超範圍,因為這種方法計算有除法,不能邊做邊mod.
優點:複雜度o(n),缺點只能求n,m極小的情況。
#include#define ll long long
using namespace std;
const ll mod = 1e9 + 7;
ll cal(int n,int m)
for(int i=1;i<=m;i++)
return ans%mod;
}int main()
首先介紹一下楊輝三角法公式
c(n,m)=c(n-1,m)+c(n-1,m-1)
複雜度o(n^2),但由於是加法,可以邊做邊mod,保證數字不會超限。
#includeconst int n = 2000 + 5;
const int mod = (int)1e9 + 7;
long long comb[n][n];//comb[n][m]就是c(n,m)
void init()
}}int main()
lucas定律:c(n,m)%p=c(n/p,m/p)*c(n%p,m%p)%p證明:
最後一步的得出詳見其實不難,自己也可以一眼看出來)
總條件:p為質數,p為非質數時可以用擴充套件盧卡斯定律,但這裡不討論!
模板一.適用於n,m,p較大的情況,複雜度大概為o(mlogn)
#include#define ll long long
using namespace std;
const ll p = (ll)1e9 + 7;
ll pow(ll a, ll b, ll m)
ans %= m;
return ans;
}ll inv(ll x, ll p)//x關於p的逆元,p為素數
ll c(ll n, ll m, ll p)//組合數c(n, m) % p
ll lucas(ll n, ll m, ll p)
int main()
return 0;
}
模板二,打表版,適用於n,m較大,p<10^6情況。複雜度為o(logn)
#include#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
const ll p = (ll)13;
ll fac[maxn];//階乘打表
void init(ll p)//此處的p應該小於1e5,這樣lucas定理才適用
ll pow(ll a, ll b, ll m)
ans %= m;
return ans;
}ll inv(ll x, ll p)//x關於p的逆元,p為素數
ll c(ll n, ll m, ll p)//組合數c(n, m) % p
ll lucas(ll n, ll m, ll p)
int main()
return 0;
}
組合數學 求組合數
對於求組合數,要根據所給資料範圍來選擇合適的演算法 這道題中所給的資料範圍適合用打表的方法直接暴力求解 先用4e6的複雜度預處理出所有的情況,再用1e4的複雜度完成詢問即可 include using namespace std const int n 2010 const int mod 1e9 ...
組合數 求組合數的幾種方法總結
求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...
計算組合數
1.防溢位 如果直接用c n,m n!n m m 來程式設計很可能會在算n!時就爆了long long,所以每一步最好把除分母也算上。所以對於c n,m 來說取m min m,n m 來算c n,m n n 1 n 2 n m 1 m m 1 m 2 1 顯然分子分母都是m項相乘,從後往前去算 先算...