组合数取余


即计算 Cnm%pC_n^m\%p .
n,mn, m 比较大时,就可以爆掉long long的范围了(据大佬说大概 n=60n=60 就会爆了). 本蒟蒻就不验证了,相信大佬的 . 其实你算个阶乘就可以了

使用C++库函数

可以使用一个众所周知的数学定理
n,m50n,m\le50,使用C++库函数tagamma .

double tgamma(double x);

tgammatgamma 是一个欧拉积分
Γ(s)=0xs1exdx \varGamma(s) = \int_{0}^{\infty} x^{s-1}e^{-x}dx\qquad
理解不了不重要,只要会用下面这个结论就行了

在整数点处取值满足
Γ(n+1)=n! \varGamma(n+1) = n!
代码十分简短 .

LL get_c(LL n, LL m)
{
        return (LL)round(tgamma(n+1)/tgamma(m+1)/tgamma(n-m+1));
}

利用杨辉恒等式

杨辉三角,是二项式系数在三角形中的一种几何排列,

1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1

不知道怎么搞居中,但相信你们能懂我意思

C00C_0^0
C10  C21  C11C_1^0 \space \space C_2^1 \space \space C_1^1
C20  C31  C32  C33C_2^0 \space \space C_3^1 \space \space C_3^2 \space \space C_3^3
C30  C41  C42  C43  C44C_3^0 \space \space C_4^1 \space \space C_4^2 \space \space C_4^3 \space \space C_4^4
C40  C51  C52  C53  C54  C55C_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

显而易见,得出杨辉恒等式: Cnm=Cn1m1+Cn1mC_n^m = C_{n-1}^{m-1} + C_{n-1}^m

如果 n,mn,m 不大(可以开 O(n2)O(n^2) 的空间),我们就可以开心暴力地打个表了 .

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;
}

利用逆元

如果 nn 已经不满足前面两种情况,在保证模数为素数的情况下,可以用逆元求解. 可以开 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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章