排列组合模板---A(n,m)和C(n,m)

一、概念

在排列组合中A与C代表不同的概念

  • A 代表的是“排列”(Arrangement 或者 Permutation),指的是从n个不同元素中取出m(1≤m≤n)个元素,按照一定的顺序排成一列,这种安排的方式称为排列。其计算公式为 A(n,m)=n!/(n−m)!

  • C 代表的是“组合”(Combination),指的是从n个不同元素中取出m(1≤m≤n)个元素,不考虑顺序合成一组的方法数。组合的计算公式为 C(n,m)=n!​/m!(n−m)!,这里的选择不关心顺序,因此数目会少于排列的情况。

简单来说,当问题涉及到顺序时使用排列(A),而当问题不涉及顺序时则使用组合(C)。 

二、模板

1.C(n,m)

这里是用了dp的思想

void init_C()//组合数:从i个元素中选j个元素根据定义求解C
{
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=i;j++)
        {
            if(!j)c[i][j]=1;//因为从i个元素中选0个元素只有一种选法就是不选
            else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;//有两种选法一种是j个元素全从i中选,另一种是1个选第i个元素剩下j-1个元素从i-1个元素中选
        }
    }
}

2.A(n,m)

我们高中都学过一个公式就是C(n,m)=A(n,m)/A(m,m),这个公式也可以看作A(n,m)=C(n,m)*A(m,m)。也就是说

从n中取m个元素并排列的方案数==从n中取m个元素不排列的方案数*m个元素的全排列

所以说我们可以用C(n,m)推出A(n,m)       

自己瞎想的不知道对不对不对再说ヾ(≧O≦)〃嗷~

​
void init_C()//组合数:从i个元素中选j个元素根据定义求解C
{
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=i;j++)
        {
            if(!j)c[i][j]=1;//因为从i个元素中选0个元素只有一种选法就是不选
            else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;//有两种选法一种是j个元素全从i中选,另一种是1个选第i个元素剩下j-1个元素从i-1个元素中选
        }
    }
}
//计算阶乘并取模--用来计算全排列
long long factorialMod(int n, int mod) {
    long long result = 1;
    for (int i = 2; i <= n; ++i) {
        result = (result * i) % mod;
    }
    return result;
}
//再根据公式得出想求的A就可以了就不写了

​

三、例题

4496. 吃水果 - AcWing题库

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2010;
const int mod=998244353;
int n,m,k;
int c[N][N];
void init_C()//组合数:从i个元素中选j个元素根据定义求解C
{
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=i;j++)
        {
            if(!j)c[i][j]=1;//因为从i个元素中选0个元素只有一种选法就是不选
            else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;//有两种选法一种是j个元素全从i中选,另一种是1个选第i个元素剩下j-1个元素从i-1个元素中选
        }
    }
}
int qmi(int m,int k)//快速幂
{
    int res=1;
    while(k)
    {
        if(k&1)
        {
            res=res*m%mod;
        }
        m=m*m%mod;
        k>>=1;
    }
    return res;
}
signed main()
{
    cin>>n>>m>>k;
    init_C();
    int ans=(c[n-1][k]*m)%mod;
    ans=ans*qmi(m-1,k)%mod;//可推理出答案=c[n-1][k]*m*(m-1)^k
    cout<<ans<<endl;
    return 0;
}

1359. 有效的快递序列数目 - 力扣(LeetCode)

这题用的是递推、dp的思想

f[i]表示订单数为i时的序列数目,f[i]包含i个订单的序列,可以将i个拆为第i个和前i-1个的序列

然后将最后一组订单i(Pi,Di)排序到长度为(i-1)*2的序列中去

分为Pi,Di连续和不连续两种情况

1、连续时的序列数为2(i-1)+1=2i-1

2、不连续时的序列数为C(2i-1,2)=(2i-1)(i-1)

两种情况加和为(2i-1)*i

又因为前面包含i-1个订单的序列也要排列

所以我们得出了递推公式f[i]=f[i-1]*(2i-1)*i。

//递推
#define ll long long
const int MOD=1e9+7;
class Solution {
public:
    int countOrders(int n) {
        if(n==1)
        {
            return 1;
        }
        ll res=1;
        for(int i=2;i<=n;i++)
        {
            res=(res*(2*i-1)*i)%MOD;
        }
        return res;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值