#include<cstdio>
const int N = 200000 + 5;
const int MOD = (int)1e9 + 7;
int F[N], Finv[N], inv[N];//F是阶乘,Finv是逆元的阶乘
void init()
{
inv[1] = 1;
for(int i = 2; i < N; i ++){
inv[i] = (MOD - MOD / i) * 1ll * inv[MOD % i] % MOD;//*1ll是将int转化为long long
}
F[0] = Finv[0] = 1;
for(int i = 1; i < N; i ++){
F[i] = F[i-1] * 1ll * i % MOD;
Finv[i] = Finv[i-1] * 1ll * inv[i] % MOD;
}
}
int comb(int n, int m){//comb(n, m)就是C(n, m)
if(m < 0 || m > n) return 0;
return F[n] * 1ll * Finv[n - m] % MOD * Finv[m] % MOD;
}
int main(){
init();
}
组合数公式:
C(n,m) = n! * inv(m!)%mod *inv((n-m)!)%mod
inv()为逆元。
#define mod 1000000007
typedef long long LL;
const int maxn = 100000 + 10;
LL fac[maxn];//乘阶表
LL power(LL a,LL b){//快速幂
a%=mod;
LL ans = 1;
while(b){
if(b&1)ans = (ans*a)%mod;
b>>=1;
a = (a*a)%mod;
}
return ans;
}
LL inv(LL a){//返回逆元(费马小定理)
return power(a,mod-2)%mod;
}
void solve(){//计算乘阶表
fac[0] = 1;
for(int i = 1;i<=maxn-1;i++){
fac[i] = (fac[i-1]*i)%mod;
}
}
LL comb(int n,int k){//返回组合数(组合数公式)
if(k>n)return 0;
return (fac[n]*inv(fac[k])%mod*inv(fac[n-k])%mod)%mod;
}
int main()
{
solve();
int n,k;
while(scanf("%d%d",&n,&k)!=EOF){
printf("%lld\n",comb(n,k));
}
return 0;
}
杨辉三角形求组合数
void YangHui() { //杨辉三角求组合数
memset(Triangle, 0, sizeof(Triangle));
for (LL i = 1; i <= 100; ++i) {
Triangle[i][0] = Triangle[i][i] = 1;
for (LL j = 1; j < i; ++j){
Triangle[i][j] = Triangle[i-1][j-1] + Triangle[i-1][j];
}
}
}
大组合数
当m和n都比较大,p反而比较小的时候,可以使用卢卡斯定理。
C(n, m) % p = C(n / p, m / p) * C(n%p, m%p) % p
typedef long long LL;
LL p[20],a[20];
int k;
LL Multiply(LL a,LL b,LL mod){//快速乘法取模
LL res = 0;
while(b){
if(b&1)res = (res +a)%mod;
b>>=1;
a = (a + a)%mod;
}
return res;
}
LL ex_gcd(LL a,LL b,LL &x,LL &y){拓展欧几里得求逆元
if(b==0){x = 1;y = 0;return a;}
LL res = ex_gcd(b,a%b,x,y);
LL temp = x;
x = y;
y = temp - a/b*y;
return res;
}
LL inv(LL a,LL b){//求逆元
LL x,y;
LL ans = ex_gcd(a,b,x,y);
if(ans!=1)return -1;
if(x<0)x = (x%b+b)%b;
return x;
}
LL comb(LL n,LL m,LL mod){//求组合数取模
if(m>n||n<0||m<0)return 0;
if(m==0||n==m)return 1;
if(m>n-m)m = n-m;
LL ca = 1,cb = 1;
for(LL i = 0;i<m;i++){
ca = ca*(n-i)%mod;//这里一定要每步取模否则超时
cb= cb*(m-i)%mod;
}
return ca*inv(cb,mod)%mod;
}
LL Lucas(LL n,LL m,LL mod){//卢卡斯定理递归版本
if(m==0)return 1;
return comb(n%mod,m%mod,mod)*Lucas(n/mod,m/mod,mod)%mod;
}