逆元求组合数
预处理阶乘和阶乘的逆元,
O
(
1
)
O(1)
O(1) 求组合数
f
a
c
fac
fac 和
i
n
v
inv
inv 数组必须开
l
o
n
g
long
long
l
o
n
g
long
long
void init()
{
fac[0] = inv[0] = 1;
fac[1] = inv[1] = 1;
for(int i = 2; i <= maxn - 9; ++i)// 一定要从2开始
fac[i] = fac[i-1] * i % mod,
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
for(int i = 1; i <= maxn - 9; ++i)
inv[i] = inv[i] * inv[i-1] % mod;
}
ll C(ll n, ll m){
if(m > n) return 0ll;
return fac[n] * inv[m] % mod * inv[n-m] % mod;
}
打表求组合数(不用求逆元
可以用于解决组合数取模时,模数为合数,无法用逆元求解的情况
当然
n
n
n 和
k
k
k 必须比较小
递归
ll C(ll n,ll k){// 记忆化递归
if(c[n][k]) return c[n][k];
if(n == k || k == 0) return c[n][k] = 1;
return c[n][k] = (C(n-1, k) + C(n-1, k-1)) % mod;
}
非递归
const int maxn(1005), mod(100003);
int tC[maxn][maxn]; //tC 表示 table of C
inline int C(int n, int k)
{
if(k > n) return 0;
return tC[n][k];
}
void calcC(int n)
{
for(int i = 0; i < n; i++)
{
tC[i][0] = 1;
for(int j = 1; j <= i; j++)
tC[i][j] = (C(i - 1, j - 1) + C(i - 1, j)) % mod;
}
}
Lucas定理
参考博客
适用情况:
C
n
m
%
m
o
d
C_n^m \ \% \ mod
Cnm % mod 中
n
n
n 大于
m
o
d
mod
mod 的情况(
m
o
d
mod
mod 一般不大于1e6)
模板
ll Lucas(ll n, ll m)
{
if(!m) return 1;
return Lucas(n / mod, m / mod) * C(n % mod, m % mod) % mod;
}
组合数看情况用哪个板子
每次只需要求
C
n
%
m
o
d
m
%
m
o
d
C_{n\%mod}^{m\%mod}
Cn%modm%mod,这样就大大减少了计算量
例题
P3807 【模板】卢卡斯定理/Lucas 定理
题意:
给定三个数,
n
,
m
,
p
n,m,p
n,m,p 的值,求
C
n
+
m
n
m
o
d
n
C_{n+m}^{n} \mod n
Cn+mnmodn 的值,
p
p
p 是质数
1
<
=
n
,
m
,
p
<
=
1
0
5
1<=n,m,p<=10^5
1<=n,m,p<=105
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
using namespace std;
const int maxn = 2e5 + 9;
//const int mod = 998244353;
ll n, m;
ll mod;
ll fac[maxn], inv[maxn];
ll q_pow(ll a, ll n, ll ans = 1){
while(n){
if(n & 1) ans=ans*a%mod;a=a*a%mod;n>>=1;
}return ans;
}
ll C(ll n, ll m)
{
if(m > n) return 0;
return fac[n] * q_pow(fac[m], mod - 2) % mod * q_pow(fac[n-m], mod - 2) % mod;
}
ll Lucas(ll n, ll m)
{
if(!m) return 1;
return Lucas(n / mod, m / mod) * C(n % mod, m % mod) % mod;
}
void work()
{
cin >> n >> m >> mod;
fac[0] = 1;
for(int i = 1; i <= n + m; ++i)
fac[i] = fac[i-1] * i % mod;
cout << Lucas(n + m, m) << endl;
}
int main()
{
ios::sync_with_stdio(0);
int TT;cin>>TT;while(TT--)
work();
return 0;
}