求组合数

Posted ignorance

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求组合数相关的知识,希望对你有一定的参考价值。

1 递推公式 C = C b a-1 + Cb-1 a-1  

时间复杂度 O(n+M )------ n是a,b的最大值,M是询问次数。

2.利用逆元求组合数取模(mod是质数用费马小定理)

预处理出阶乘和阶乘逆元 最后套公式求 C

时间复杂度 O(M + nlog(n))

#include <iostream>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <stack>
#define FT(a, b) memset(a, b, sizeof(a))
#define FAT(a) memset(a, 0, sizeof(a))
using namespace std;
typedef long long ll;
const int M = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int t;
ll Factorial[M], InFactorial[M];
ll qpower(ll a, ll b)
{
    ll res = 1;
    while (b)
    {
        if (b & 1)
            res = (res * a) % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res % mod;
}
int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("/home/wjy/code/c++/in.txt", "r", stdin);
#endif
    Factorial[0] = InFactorial[0] = 1;
    for (int i = 1; i < M; i++)
    {
        Factorial[i] = Factorial[i - 1] * i % mod;
        InFactorial[i] = InFactorial[i - 1] * qpower(i, mod - 2) % mod;
    }
    scanf("%d", &t);
    while (t--)
    {
        ll a, b;
        scanf("%lld%lld", &a, &b);
        printf("%lld
", ((Factorial[a] % mod * InFactorial[b]) % mod * InFactorial[a - b]) % mod);
    }

    return 0;
}

3.Lucas 定理 

C≡ Cb%p a%p * Cb/p a/p (mod p)

时间复杂度 : (M*logp N * log p *p)

#include <iostream>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <stack>
#define FT(a, b) memset(a, b, sizeof(a))
#define FAT(a) memset(a, 0, sizeof(a))
using namespace std;
typedef long long ll;
const int M = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int t;
ll p;
ll qpower(ll a, ll b)
{
    ll res = 1;
    while (b)
    {
        if (b & 1)
            res = (res * a) % p;
        a = a * a % p;
        b >>= 1;
    }
    return res % p;
}
ll C(ll a, ll b)
{
    ll res = 1;
    for (int i = 1, j = a; i <= b; i++, j--)
    {
        res = res * j % p * qpower(i, p - 2) % p % mod;
    }
    return res;
}
ll lucas(ll a, ll b)
{
    if (a < p && b < p)
        return C(a, b);
    else
        return C(a % p, b % p) * lucas(a / p, b / p) % p;
}
int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("/home/wjy/code/c++/in.txt", "r", stdin);
#endif
    scanf("%d", &t);
    while (t--)
    {
        ll a, b;
        scanf("%lld%lld%lld", &a, &b, &p);
        printf("%lld
", lucas(a, b));
    }
    return 0;
}

以上是关于求组合数的主要内容,如果未能解决你的问题,请参考以下文章

AcWing 888. 求组合数 IV(高精度求组合数问题)

线性求逆元 组合数

课程作业2

求组合数小结

求组合数

POJ-2992 Divisors---组合数求因子数目