C语言实现组合式的计算

先挖个坑,整理了一下算法笔记中的思路,具体代码之后补上,点击跳转这个链接里有po主码的算法笔记里的代码,本文中引用了里面的部分内容

组合式定义:
在这里插入图片描述
性质:
1.C(n,m)=C(n,n-m)
2.C(n,n)=C(0,0)=1

方法一:通过定义式直接计算

typedef long long int LL;
LL C(LL n, LL m)
{
    LL ans = 1;
    for(LL i=1; i<=n; i++)
        ans*=i;
    for(LL i=1; i<=m; i++)
        ans/=i;
    for(LL i=1; i<=n-m; i++)
        ans/=i;
    return ans;
}

方法二:通过递推公式计算
C(n,m)=C(n-1,m-1)+C(n-1,m)

LL C(LL n, LL m)
{
    if(m==0||m==n) return 1;
    return C(n-1, m) + C(n-1, m-1);
}

优化:通过表记录,避免重复运算

LL res[67][67] ={0};
LL C(LL n, LL m)
{
    if(m==0||m==n)
        return 1;
    if(res[n][m]!=0) return res[n][m];
    return res[n][m] = C(n-1,m)+C(n-1, m-1);
}

或,提前计算出整张表

const int n=60;
void calC()
{
    for(int i=0; i<=n; i++)
        res[i][0] =res[i][i]=1;//初始化边界
    for(int i=2; i<=n; i++)
        for(int j=0; j<=i/2; j++)
        {
            res[i][j] = res[i-1][j] +res[i-1][j-1];
            res[i][i-j] = res[i][j]; //C(i,i-j) = C(i,j)
        }
}

方法三:通过定义式的变形
在这里插入图片描述

LL C(LL n, LL m)
{
    LL ans = 1;
    for(LL i=1; i<=m; i++)
        ans = ans*(n-m+i)/i;//注意一定要先乘再除
    return ans;
}

那么如果要计算C(n,m)%p呢?
方法一:根据递推公式

LL res[1010][1010] ={0};
LL C(LL n, LL m, int p)
{
    if(m==0||m==n)
        return 1;
    if(res[n][m]!=0) return res[n][m];
    return res[n][m] = C(n-1,m)+C(n-1, m-1) % p;
}


int n;
void calC()
{
    for(int i=0; i<=n; i++)//初始化边界
        res[i][0] = res[i][i]=1;
    for(int i=2; i<=n; i++)
        for(int j=0; j<=i/2; j++)
        {
            res[i][j] = (res[i-1][j] + res[i-1][j-1]) % p ;
            res[i][i-j] = res[i][j]; //C(i,i-j) = C(i,j)
        }
}

方法二:根据定义式

int prime[maxn];//使用筛法得到的素数表
int C(int n, int m, int p)
{
    for(int i=0; prime[i]<=n; i++)
    {
        //计算C(n,m)中prime[i]的指数c, cal(n,k)为n!中含质因子k的个数
        int c = cal(n, prime[i]) - cal(m,prime) - cal(n-m, prime);
        //快速幂计算prime^c%p;
        ans =  ans *binaryPow(prime[i], c, p)%p;
    }
    return ans;
}

方法三:根据定义式的变形*
方法四:Lucas定理

扫描二维码关注公众号,回复: 6013622 查看本文章
int Lucas(int n, int m)
{
    if(m==1)  return 1;
    return C(n%p, m%p) * Lucas(n/p, m/p)%p;
}

猜你喜欢

转载自blog.csdn.net/weixin_43835911/article/details/89514333
今日推荐