组合数学学习笔记

组合数1

  • 给定 n 组询问,每组询问给定两个整数 a,b,请你输出 \(C_a^{b}\bmod(10^9+7)\) 的值

  • 数据范围

\[1≤n≤10000 \]

\[1≤b≤a≤2000 \]

上过小学的应该都知道

\[C_a^{b} = \frac{a\times (a - 1) \dots (a -b +1)}{1 \times 2 \times 3 \dots b} \]

\[C_a^{b} = \frac{!a}{!b \times !(a-b)} \]

有递推式

\[\color{Red}C_a^{b} = C_a^{b-1} + C_{a -1}^{b -1} \]

\[n^2 \]

#include <iostream>
#include <algorithm>

using namespace std;

const int N =2015,MOD = 1e9 + 7; 

int c[N][N];

void indck()
{
    for(int i = 0 ; i < N ; i ++)
        for(int j = 0 ; j <= i ; j ++ )
        if(!j)c[i][j] = 1;
        else c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % MOD;
}


int n;

int main()
{
    
    indck();
    cin >> n ;//scanf("%d",);
    while(n -- )
    {
        int a,b;
        scanf("%d%d", &a, &b);
        printf("%d\n",c[a][b]);
    }

    return 0;

}

组合数2

给定 n 组询问,每组询问给定两个整数 a,b,请你输出 \(C_a^{b}\bmod(10^9+7)\)

\[1≤n≤10000 \]

\[1≤b≤a≤105 \]

  • 因为

\[C_a^{b} = \frac{!a}{!b \times !(a-b)} \]

我们可以预处理阶乘\(fact_i\),逆元\(infact_i\)

\[\color{Red}C_a^{b} = faet_a \times infact_{b - a} \times infact_{b} \]

#include <iostream>
#include <cstdio>

using namespace std;


typedef long long LL;

const int N = 100010,mod = 1e9 + 7;

int fact[N],infact[N];

int qmi(int a,int k,int p)
{
    int res = 1;
    while(k)
    {
        if(k&1)res = (LL)res * a % p;
        a = (LL)a  * a % p;
        k >>= 1;
    }
    return res;
}

int main()
{
    fact[0] = infact[0] =  1;

    for(int i = 1 ; i < N ; i++ )
    {
        fact[i] =(LL)fact[i - 1] * i % mod;
        infact[i] = (LL)infact[i - 1] * qmi(i,mod - 2,mod) % mod;
    }

    int n;
    scanf("%d",&n);
    while(n--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%d\n",(LL)fact[a] * infact[a - b] % mod *  infact[b] % mod);
    }
    return  0;
}






\[nlog(n) \]

求组合数3

给定 n 组询问,每组询问给定三个整数 a,b,p,其中 p 是质数,请你输出 \(C^b_{a} \bmod p\) 的值。

\[1≤n≤20, 1≤b≤a≤1018, 1≤p≤105, \]

卢卡斯定理

\[\huge \color {Orange}Lucas \]

有结论

\[C_b^a \equiv C_{b \bmod p}^{a \bmod p} \times C_{b/p}^{a/p} \]

\[p\cdot \log{n}\log{p} \]

\[a = a_k \times p^0 + a_{k-1} \cdots \times p^0 \]

\[b = b_k \times p^0 + b_{k-1} \cdots \times p^0 \cdots \]

\[(1 + x)^{p} = 1 + C_p^1 \times + C_p^2 + \cdots C_p^b \]

$\because p $是质数,p中不包含任意小于p的质因子

\(\therefore\)

\[(1 + x)^{p} = 1 + C_p^1 \times x+ C_p^2 \times x^2+ \cdots C_p^b \times x^{k - 1} \]

\[\because C_{p_k}^{1} \sim C_k^{p_k} (\bmod p) = 0 \]

\[\begin{array}{l} (1 + x)^a = (1 + x)^{a_0} \times ((1 + x)^{p_1})^{a_1} \times ((1 + x)^{p_2})^{a_2} \cdots ((1 + x)^{p_b})^{a_k}\\ (1 + x)^a = (1 + x)^{a_0} \times (1 + x^{p_1})^{a_1} \times (1 + x^{p2})^{a_2} \cdots ( 1 + x^b)^{a_k} \end{array} \]

\[C_a^b \equiv C_{a_k}^{b_k} \times C_{a_{k - 1} }^{b_{k - 1}} \cdots C_{a_{0}}^{b_{0}} \]

\[\begin{array}{l} b_i > a_i\\ C_a^b = 0\\ \end{array} \]

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace  std;
typedef long long LL;
int p;

int qmi(int a,int k)
{
    int res = 1;
    while(k)
    {
        if(k&1)res = (LL)res * a % p;
        a = (LL) a * a %p;
        k >>= 1;
    }
    return res;

}

int C(LL a,LL b)
{
    int res = 1;
    for(int i = 1 , j = a ; i <= b;i ++ , j --)
    {
        res = (LL)res * j % p;
        res = (LL)res *qmi(i,p - 2) % p;//除i = 乘i的逆元
    }
    return res;
}

int lucas(LL a, LL b)
{
    if(a < p && b < p )return C(a,b);
    return (LL)C(a%p,b%p) * lucas(a/p,b/p) % p;

}

int main()
{
    int n;
    scanf("%d", &n);
    while(n--)
    {
        LL a,b;
        scanf("%lld%lld%d",&a,&b,&p);
        cout << lucas(a,b) << endl;
    }
    return 0;
}

组合数4

输入 a,b,求 \(C_a^b\)的值。
注意结果可能很大,需要使用高精度计算。

  1. 分解质因数
  2. 求每个质数的次数
    $ p_1^{k_1} \times p_2^{k_2}\cdots \times p_k^{k_k}$
  3. 用高精度乘法每个质因子

\[C_a^{b} = \frac{a\times (a - 1) \dots (a -b +1)}{1 \times 2 \times 3 \dots b} \]

\[C_a^{b} = \frac{!a}{!b \times !(a-b)} \]

\[\begin{array}{l} !a = \left \lfloor \frac{a}{p} \right \rfloor + \left \lfloor \frac{a}{p^2} \right \rfloor + \left \lfloor \frac{a}{p^3}\right \rfloor \cdots(p^x > a)\\ \end{array} \]

\( \left \lfloor \frac{a}{p} \right \rfloor \)为p的倍数
\( \left \lfloor \frac{a}{p^2} \right \rfloor \)\(p^2\)的倍数
\(\left \lfloor \frac{a}{p^3} \right \rfloor \)\(p^3\)的倍数

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 50000;

int prime[N],cnt;
int sum[N];
bool st[N];

void get_prime(int n)
{
    for(int i = 2 ; i <= n ; i ++)
    {
    if(!st[i])prime[cnt++] = i;
    for(int j = 0 ; prime[j] <= n/i ; j ++)
    {
        st[prime[j] * i] = true;
        if(i % prime[j]  == 0)break;
    }

    }
    

}

int get(int n,int p)
{
    int res = 0;
    while(n)
    {
        res += n / p;
        n /= p;
    }
    return res;
}

vector<int> mul(vector<int>a,int b)
{
    
    vector<int> c;
    int t = 0;
    for(int i = 0 ; i < a.size() ; i ++ )
    {
        t += a[i] * b;
        c.push_back(t%10);
        t /= 10;

    }
    while(t)
    {
        c.push_back(t % 10);
        t /= 10;
    }
    // while(C.size()>1 && C.back()==0) C.pop_back();
    //考虑b==0时才有pop多余的0
    return c;

}

int main()
{
    int a,b;
    cin >> a >> b;
    get_prime(a);
    
    for(int i = 0 ; i < cnt ; i ++ )
    {
        int p = prime[i];
        sum[i]= get(a,p) - get(b,p) - get(a - b,p);
    }
    
    vector<int>res;
    
    res.push_back(1);

    for(int i = 0 ; i < cnt ; i ++ )
        for(int j = 0 ; j < sum[i] ; j ++ )
        res = mul(res,prime[i]);

    for(int i = res.size() - 1 ; i >= 0 ; i --) printf("%d",res[i]);
    puts("");
    return 0;


}
posted @ 2022-07-12 22:22  Erfu  阅读(25)  评论(0)    收藏  举报