即计算 C n m % p C_n^m\%p Cnm%p .
当 n , m n, m n,m 比较大时,就可以爆掉long long的范围了(据大佬说大概 n = 60 n=60 n=60 就会爆了). 本蒟蒻就不验证了,相信大佬的 .
使用C++库函数
可以使用一个众所周知的数学定理
当
n
,
m
≤
50
n,m\le50
n,m≤50 时,使用C++库函数tagamma .
double tgamma(double x);
t
g
a
m
m
a
tgamma
tgamma 是一个欧拉积分
Γ
(
s
)
=
∫
0
∞
x
s
−
1
e
−
x
d
x
\varGamma(s) = \int_{0}^{\infty} x^{s-1}e^{-x}dx\qquad
Γ(s)=∫0∞xs−1e−xdx
理解不了不重要,只要会用下面这个结论就行了
在整数点处取值满足
Γ
(
n
+
1
)
=
n
!
\varGamma(n+1) = n!
Γ(n+1)=n!
代码十分简短 .
LL get_c(LL n, LL m)
{
return (LL)round(tgamma(n+1)/tgamma(m+1)/tgamma(n-m+1));
}
利用杨辉恒等式
杨辉三角,是二项式系数在三角形中的一种几何排列,
不知道怎么搞居中,但相信你们能懂我意思
C
0
0
C_0^0
C00
C
1
0
C
2
1
C
1
1
C_1^0 \space \space C_2^1 \space \space C_1^1
C10 C21 C11
C
2
0
C
3
1
C
3
2
C
3
3
C_2^0 \space \space C_3^1 \space \space C_3^2 \space \space C_3^3
C20 C31 C32 C33
C
3
0
C
4
1
C
4
2
C
4
3
C
4
4
C_3^0 \space \space C_4^1 \space \space C_4^2 \space \space C_4^3 \space \space C_4^4
C30 C41 C42 C43 C44
C
4
0
C
5
1
C
5
2
C
5
3
C
5
4
C
5
5
C_4^0 \space \space C_5^1 \space \space C_5^2 \space \space C_5^3 \space \space C_5^4 \space \space C_5^5
C40 C51 C52 C53 C54 C55
显而易见,得出杨辉恒等式: C n m = C n − 1 m − 1 + C n − 1 m C_n^m = C_{n-1}^{m-1} + C_{n-1}^m Cnm=Cn−1m−1+Cn−1m
如果
n
,
m
n,m
n,m 不大(可以开
O
(
n
2
)
O(n^2)
O(n2) 的空间),我们就可以开心暴力地打个表了 .
LL __[maxn][maxn];
LL get_c(LL n)
{
for (int i = 0; i <= n; i++)
for (int j = 0; j <= i; j++)
__[i][j] = (j == 0 || j == i) ? 1 : (__[i-1][j-1]+__[i-1][j])%mod;
}
利用逆元
如果 n n n 已经不满足前面两种情况,在保证模数为素数的情况下,可以用逆元求解. 可以开 O ( n ) O(n) O(n) 的空间.
#define LL long long
const int mod = 1e9+10;
const int maxn = 1e5+10;
LL get_c(LL n, LL m)
{
static LL M = 0, in[maxn], mul[maxn] = {1}, ans[maxn] = {1};
while (++M <= n)
{
in[M] = M == 1 ? 1 : (mod - mod/M) * in[mod%M] % mod;
mul[M] = mul[M-1]*M%mod;
ans[M] = ans[M-1] * in [M] % mod;
}
return mul[n]*ans[m] % mod * ans[n-m] % mod;
}