码迷,mamicode.com
首页 > 其他好文 > 详细

求组合数

时间:2020-01-18 19:40:32      阅读:74      评论:0      收藏:0      [点我收藏+]

标签:log   复杂   ret   efi   for   最大值   can   span   c++   

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\n", ((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\n", lucas(a, b));
    }
    return 0;
}

求组合数

标签:log   复杂   ret   efi   for   最大值   can   span   c++   

原文地址:https://www.cnblogs.com/ignorance/p/12206537.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!