组合数学学习笔记

组合数1

  • 给定 n 组询问,每组询问给定两个整数 a,b,请你输出 Cabmod(109+7) 的值

  • 数据范围

1n10000

1ba2000

上过小学的应该都知道

Cab=a×(a1)(ab+1)1×2×3b

Cab=!a!b×!(ab)

有递推式

Cab=Cab1+Ca1b1

n2

#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,请你输出 Cabmod(109+7)

1n10000

1ba105

  • 因为

Cab=!a!b×!(ab)

我们可以预处理阶乘facti,逆元infacti

Cab=faeta×infactba×infactb

#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 是质数,请你输出 Cabmodp 的值。

1n20,1ba1018,1p105,

卢卡斯定理

Lucas

有结论

CbaCbmodpamodp×Cb/pa/p

plognlogp

a=ak×p0+ak1×p0

b=bk×p0+bk1×p0

(1+x)p=1+Cp1×+Cp2+Cpb

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

(1+x)p=1+Cp1×x+Cp2×x2+Cpb×xk1

Cpk1Ckpk(modp)=0

(1+x)a=(1+x)a0×((1+x)p1)a1×((1+x)p2)a2((1+x)pb)ak(1+x)a=(1+x)a0×(1+xp1)a1×(1+xp2)a2(1+xb)ak

CabCakbk×Cak1bk1Ca0b0

bi>aiCab=0

#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,求 Cab的值。
注意结果可能很大,需要使用高精度计算。

  1. 分解质因数
  2. 求每个质数的次数
    p1k1×p2k2×pkkk
  3. 用高精度乘法每个质因子

Cab=a×(a1)(ab+1)1×2×3b

Cab=!a!b×!(ab)

!a=ap+ap2+ap3(px>a)

ap为p的倍数
ap2p2的倍数
ap3p3的倍数

#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 @   Erfu  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示