组合数取余


即计算 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,m50,使用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)=0xs1exdx
理解不了不重要,只要会用下面这个结论就行了

在整数点处取值满足
Γ ( 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));
}

利用杨辉恒等式

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

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

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

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=Cn1m1+Cn1m

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

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值