组合c(m,n)的计算方法

2024-09-08 08:58
文章标签 组合 计算方法

本文主要是介绍组合c(m,n)的计算方法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

   问题:求解组合数C(n,m),即从n个相同物品中取出m个的方案数,由于结果可能非常大,对结果模10007即可。


      共四种方案。ps:注意使用限制。

方案1:

暴力求解,C(n,m)=n*(n-1)*...*(n-m+1)/m!,n<=15

int Combination(int n, int m) 
{ const int M = 10007; int ans = 1; for(int i=n; i>=(n-m+1); --i) ans *= i; while(m) ans /= m--; return ans % M; 
} int Combination(int n, int m)
{const int M = 10007;int ans = 1;for(int i=n; i>=(n-m+1); --i)ans *= i;while(m)ans /= m--;return ans % M;
}

方案2:

打表,C(n,m)=C(n-1,m-1)+C(n-1,m),n<=10,000

const int M = 10007; 
const int MAXN = 1000; 
int C[MAXN+1][MAXN+1]; 
void Initial() 
{ int i,j; for(i=0; i<=MAXN; ++i) { C[0][i] = 0; C[i][0] = 1; } for(i=1; i<=MAXN; ++i) { for(j=1; j<=MAXN; ++j) C[i][j] = (C[i-1][j] + C[i-1][j-1]) % M; } 
} 
int Combination(int n, int m) 
{ return C[n][m]; 
} const int M = 10007;
const int MAXN = 1000;
int C[MAXN+1][MAXN+1];
void Initial()
{int i,j;for(i=0; i<=MAXN; ++i){C[0][i] = 0;C[i][0] = 1;}for(i=1; i<=MAXN; ++i){for(j=1; j<=MAXN; ++j)C[i][j] = (C[i-1][j] + C[i-1][j-1]) % M;}
}
int Combination(int n, int m)
{return C[n][m];
}

方案3:

质因数分解,C(n,m)=n!/(m!*(n-m)!),C(n,m)=p1a1-b1-c1p2a2-b2-c2…pkak-bk-ck,n<=10,000,000

#include <cstdio>  
const int maxn=1000000; 
#include <vector>  
using namespace std; 
bool arr[maxn+1]={false}; 
vector<int> produce_prim_number() 
{ vector<int> prim; prim.push_back(2); int i,j; for(i=3;i*i<=maxn;i+=2) { if(!arr[i]) { prim.push_back(i); for(j=i*i;j<=maxn;j+=i) arr[j]=true; } } while(i<maxn) { if(!arr[i]) prim.push_back(i); i+=2; } return prim; 
} 
//计算n!中素数因子p的指数  
int cal(int x,int p) 
{ int ans=0; long long rec=p; while(x>=rec) { ans+=x/rec; rec*=p; } return ans; 
} 
//计算n的k次方对m取模,二分法  
int pow(long long n,int k,int M) 
{ long long ans=1; while(k) { if(k&1) { ans=(ans*n)%M; } n=(n*n)%M; k>>=1; } return ans; 
} 
//计算C(n,m)  
int combination(int n,int m) 
{ const int M=10007; vector<int> prim=produce_prim_number(); long long ans=1; int num; for(int i=0;i<prim.size()&&prim[i]<=n;++i) { num=cal(n,prim[i])-cal(m,prim[i])-cal(n-m,prim[i]); ans=(ans*pow(prim[i],num,M))%M; } return ans; 
} 
int main() 
{ int m,n; while(~scanf("%d%d",&m,&n),m&&n) { printf("%d\n",combination(m,n)); } return 0; 
} 

方案4:

Lucas定理,将m,n化为p进制,有:C(n,m)=C(n0,m0)*C(n1,m1)...(mod p),算一个不是很大的C(n,m)%p,p为素数,化为线性同余方程,用扩展的欧几里德定理求解,n在int范围内,修改一下可以满足long long范围内。



#include <stdio.h>
const int M = 2013;
int ff[M+5];  //打表,记录n!,避免重复计算//求最大公因数
int gcd(int a,int b)
{if(b==0)return a;elsereturn gcd(b,a%b);
}//解线性同余方程,扩展欧几里德定理
int x,y;
void Extended_gcd(int a,int b)
{if(b==0){x=1;y=0;}else{Extended_gcd(b,a%b);long t=x;x=y;y=t-(a/b)*y;}
}//计算不大的C(n,m)
int C(int a,int b)
{if(b>a)return 0;b=(ff[a-b]*ff[b])%M;a=ff[a];int c=gcd(a,b);a/=c;b/=c;Extended_gcd(b,M);x=(x+M)%M;x=(x*a)%M;return x;
}//Lucas定理
int Combination(int n, int m)
{int ans=1;int a,b;while(m||n){a=n%M;b=m%M;n/=M;m/=M;ans=(ans*C(a,b))%M;}return ans;
}int main()
{int i,m,n;ff[0]=1;for(i=1; i<=M; i++) //预计算n!ff[i]=(ff[i-1]*i)%M;while(~scanf("%d%d",&n, &m)){printf("%d\n",Combination(n,m));}return 0;
}


这篇关于组合c(m,n)的计算方法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1147673

相关文章

hdu4869(逆元+求组合数)

//输入n,m,n表示翻牌的次数,m表示牌的数目,求经过n次操作后共有几种状态#include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdlib.h>#includ

Go组合

摘要 golang并非完全面向对象的程序语言,为了实现面向对象的继承这一神奇的功能,golang允许struct间使用匿名引入的方式实现对象属性方法的组合 组合使用注意项 使用匿名引入的方式来组合其他struct 默认优先调用外层方法 可以指定匿名struct以调用内层方法 代码 package mainimport ("fmt")type People struct{}type Pe

IBS和IBD的区别和计算方法介绍

大家好,我是邓飞。 今天介绍一下IBS和IBD的区别: IBS(肠易激综合症)和IBD(炎症性肠病)是两种不同的消化系统疾病,主要区别如下: IBS(Irritable Bowel Syndrome):是一种功能性肠道疾病,主要表现为腹痛、腹胀、腹泻或便秘,症状通常与饮食、压力和心理因素相关,没有明显的器质性病变。 IBD(Inflammatory Bowel Disease):是一组

代码随想录训练营day37|52. 携带研究材料,518.零钱兑换II,377. 组合总和 Ⅳ,70. 爬楼梯

52. 携带研究材料 这是一个完全背包问题,就是每个物品可以无限放。 在一维滚动数组的时候规定了遍历顺序是要从后往前的,就是因为不能多次放物体。 所以这里能多次放物体只需要把遍历顺序改改就好了 # include<iostream># include<vector>using namespace std;int main(){int n,m;cin>>n>>m;std::vector<i

INDEX+SMALL+IF+ROW函数组合使用解…

很多人在Excel中用函数公式做查询的时候,都必然会遇到的一个大问题,那就是一对多的查找/查询公式应该怎么写?大多数人都是从VLOOKUP、INDEX+MATCH中入门的,纵然你把全部的多条件查找方法都学会了而且运用娴熟,如VLOOKUP和&、SUMPRODUCT、LOOKUP(1,0/....,但仍然只能对这种一对多的查询望洋兴叹。   这里讲的INDEX+SMALL+IF+ROW的函数组合,

代码随想录算法训练营Day37|完全背包问题、518.零钱兑换II、377. 组合总和 Ⅳ、70. 爬楼梯(进阶版)

完全背包问题                  和01背包最大区别就是一个物品可以重复放多次,因此遍历空间时可以从前往后。 import java.util.*;public class Main{public static void main (String[] args) {Scanner sc = new Scanner(System.in);int m = sc.nextInt

【内网】ICMP出网ew+pingtunnel组合建立socks5隧道

❤️博客主页: iknow181 🔥系列专栏: 网络安全、 Python、JavaSE、JavaWeb、CCNP 🎉欢迎大家点赞👍收藏⭐评论✍ 通过环境搭建,满足以下条件: 攻击机模拟公网vps地址,WEB边界服务器(Windows Server 2008)模拟公司对外提供Web服务的机器,该机器可以通内网,同时向公网提供服务。内网同网段存在一台Windows内网服务

PyPortfolioOpt:Python中的投资组合优化工具

PyPortfolioOpt:Python中的投资组合优化工具 在金融领域,投资组合优化是一个关键的环节,它帮助投资者在追求最大回报的同时管理风险。今天,我们将探索一个名为PyPortfolioOpt的Python库,它提供了一系列的工具和算法,用于构建和优化投资组合。 概览 PyPortfolioOpt是一个开源的Python库,专门用于金融投资组合的优化。它包括经典的有效前沿、Black

读软件设计的要素03概念的组合

1. 概念的组合 1.1. 概念不像程序那样,可以用较大的包含较小的 1.1.1. 每个概念对用户来说都是平等的,软件或系统就是一组串联运行的概念组合 1.2. 概念是通过操作来同步组合的 1.2.1. 同步并不增加新的概念操作,但会限制已有的操作,从而消除一些独立概念可能会出现的操作序列 1.3. 在自由组合中,概念彼此独立,仅受一些记录的约束,这些约束是为了确保概念对事物观点的一

java设计模式day03--(结构型模式:代理模式、适配器模式、装饰者模式、桥接模式、外观模式、组合模式、享元模式)

5,结构型模式 结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。 由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: 代理模式 适配器模式 装饰者模式 桥接模式 外观模式 组合模式