【概念】

1.组合

从 n 个元素的集合 S 中,无序的选出 r 个元素,叫做 S 的一个 r 组合。

如果两个组合中,至少有一个元素不同,它们就被认为是不同的组合。

2.不可重组合数

所有不同组合的个数,叫做组合数,记作: 或 

由于每一种组合都可以扩展到 r!种排列,而总排列为 A(n,r) ,所以组合数

特别的,C(n,0)=1

3.可重复组合数

从 n 个不同的元素中,无序的选出 r 个元素组成一个组合,且允许这 r 个元素重复使用,则称这样的组合为可重复组合。

其组合数记为:

4.不相邻组合数

从 A={1,2,...,n} 中选取 m 个不相邻的组合,其组合数为:

例题:

① 一班有10名同学,二班有8名同学,现每个班级要选出2名学生参加一个座谈会,求有多少种选法?

根据组合数与乘法原理,共有:C(10,2)*C(8,2)=1260 种

② 某班有10名同学,有4名女同学,现要选出3名学生,其中至少有一名女同学,求有多少种选法?

根据组合数与加法原理,共有:C(4,1)*C(6,2)+C(4,2)*C(6,1)+C(4,3)*C(6,0)=60+36+4=100 种

【组合数常用公式】

1)

2)

3)

4)(二项式定理)

特殊展开:

5) 为奇数时有 n&m=n

【求组合数的方法】

首先 C(n,m) 的值一定是自然数,因为连续 m 个自然数的积一定被 m! 整除,因此求 C(n,m) 的值关键在于如何避免做除法。

1.递归计算

利用公式  来递归的计算组合数

LL cal(LL n,LL k){if(n<k||k==0)return 0;if(n==k||k==1)return 1;return cal(n-1,k-1)+k*cal(n-1,k);
}
int main(){LL n,k;cin>>n>>k;cout<<cal(n,k)<<endl;return 0;
}

2.杨辉三角打表

利用公式 ,将计算 C(n,r) 的过程化为加法来做,由于二项式展开系数的与杨辉三角一致,故该方法的实质就是求杨辉三角第 n 行,第 r 列上的数。

int f[N][N];
int main()
{f[0][0]=1;for(int i=1;i<=N-1;i++)for(int j=1;j<=i+1;j++)f[i][j]=f[i-1][j]+f[i-1][j-1];int n,r;scanf("%d%d",&n,&r);printf("%d\n",f[n+1][r+1]);return 0;
}

3.公式化简打表

,由于除以 m,因此相对没那么容易越界

int C[N];
void calculate(int n,int m){//C[i]即为C(n,i)的值C[0]=1;for(int i=1;i<=n;i++)C[i]=C[i-1]*(n-i+1)/i;
}

4.约分求重数

约分之后,分母即会变为 1,借此将除法化为乘法,约分方法是计算 1 到 n 之间的任意一个质数在 C(n,r) 的重数。

具体做法是对分子分母上的每个数分解质因子,用一个数组 C[] 来记录重数,若分子上的数分解一个质因子 p,则 C[p]++,反之若分母上的数分解出质因子 p,则 C[p]--,最后将每个质因子按其重数连乘即可。

将公式化为 ,通过直接计算质数 p 在 n! 中的重数而得到数组 C[],质数 p 在自然数 n 中的重数是指自然数 n 的质因数分解式质数 p 出现的次数,质数 p 在 n! 的重数为: ,根据公式:,可以递推的求出 p 在 n!中的重数。

例如:72=2*2*2*3*3,质数 2 在 72 的重数是 3,质数 3 在 72 的重数是 2;n=1000,p=3时,有 1000 div 3+1000 div 9+1000 div 27+1000 div 81+1000 div 243+1000 div 729=333+111+37+12+4+1=498,因此 1000!能被 3^498 整除,但不能被 3^499 整除,使用递推公式后,有:333 div 3=111 ,111 div 3=37,37 div 3=12,12 div 3=4,4 div 3=1

程序实现时,先求出 1 到 n 间所有质数,再对每个质数求重数,从而计算从 n-r+1 到 n 的因子的重数与从 1 到 r 的因子的重数,前者减去后者,C[i] 中所存储的即为约分后质数因子的重数,再利用高精度加法,将答案存储,最后倒序输出即可。

#include<cstdio>
#include<cstring>
#include<vector>
const int N=30000;
vector<int> prime,C;
bool vis[N];
int res[10];
void Get_Prime()
{memset(vis,true,sizeof(vis));for(int i=2;i<=N;i++){if(vis[i]){prime.push_back(i);//存储质数C.push_back(0);//当前质数的重数为0for(int j=i*i;j<=N;j+=i)//筛除所有以i为因子的数vis[j]=false;}}
}
void Add(int n,int p)//记录重数个数
{for(int i=0;i<prime.size()&&prime[i]<=n;i++){while(!(n%prime[i])){n/=prime[i];C[i]+=p;}}
}
int main()
{Get_Prime();//打表获取质数int n,r;scanf("%d%d",&n,&r);if(r>n-r)//根据公式C(n,r)=C(n,n-r)简化计算r=n-r;for(int i=0;i<r;i++){Add(n-i,1);//将n-r+1到n的因子加到C中去Add(i+1,-1);//将1到r的因子从C中减去}memset(res,0,sizeof(res));res[0]=1;for(int i=0;i<prime.size();i++)//枚举所有质数{for(int j=0;j<C[i];j++)//枚举对应质数的重数{for(int k=0;k<10;k++)res[k]*=prime[i];for(int k=0;k<10;k++)//高精存储答案{if(k<9)res[k+1]+=res[k]/10;res[k]%=10;}}}for(int i=9;i>=0;i--)printf("%d",res[i]);printf("\n");return 0;
}

【例题】

  • Rooks(LightOJ-1005)(排列+组合):点击这里
  • Wall Painting(HDU-4810)(杨辉三角组合数打表+二进制枚举):点击这里
  • Combinations(POJ-1306)(公式化简法求组合数):点击这里
  • Binomial Showdown(POJ-2249)(公式化简法求组合数):点击这里
  • 集合的划分(信息学奥赛一本通-T1315)(递归法求组合数):点击这里

组合数学 —— 组合数相关推荐

  1. 组合数学 - 组合数的个数

    组合数的个数 输入一个n,然后输入n个一位数,求这n个数组成的不重复出现的整数的总和. Mean: 略 analyse: 这样的数可以是1~n位,总共数的数目为:P(n,1)+p(n,2)+p(n,3 ...

  2. 组合数学 —— 组合数取模

    [概述] 组合数取模,即计算组合数 ,由于 ,同余定理对除法不适用,因此需要使用别的方法来解决这个问题 常见的方法有:使用逆元对组合数取模.递推打表取模.卢卡斯定理.扩展卢卡斯定理等,这些方法应用的场 ...

  3. 组合数学 —— 组合数取模 —— 卢卡斯定理与扩展卢卡斯定理

    [卢卡斯定理] 1.要求:p 是质数,m.n 很大但 p 很小 或者 n.m 不大但大于 p 2.定理内容 其中, 3.推论 当将 n 写成 p 进制:,将 m 写成 p 进制: 时,有: 4.实现 ...

  4. 组合数学 —— 组合数取模 —— 逆元与递推打表

    [逆元求法] 1.要求:p 是质数 2.时间复杂度:O(n) 3.求解  的步骤: 1)通过循环,预先算好所有小于 N 的阶乘(%p)的结果,存到数组 fac[] 中 (fac[i] = i!%p) ...

  5. [组合数学]组合数有关的公式及常用求和

    O(logn)求组合数 fac[maxn] = {1, 1, 2}; ll C(int n, int m){return (fac[n] * quickpow((fac[m] * fac[n - m] ...

  6. 省选+NOI 第八部分 数论

    1.线性基 线性回归-线性基函数模型 线性回归-线性基函数模型_哔哩哔哩_bilibili 0219数论寒假作业选讲2[线性基] 0219数论寒假作业选讲2[线性基]_哔哩哔哩_bilibili 线性 ...

  7. ACM比赛经验、刷题记录及模板库总结(更新中)

    前言 本文所提及的部分题目代码,可以在我的Github上找到 第一部分 经验分享及感受 第二部分 刷题记录 一.基础算法&程序语言 //strlen()函数的复杂度是O(n)要小心 //截取字 ...

  8. OI常用的数学知识大全(持续更新)

    OI常用的数学知识总结 本文持续更新-- 总结一下OI中的玄学数学知识 先列个单子,from秦神 数论 模意义下的基本运算和欧拉定理 筛素数和判定素数欧几里得算法及其扩展[finish] 数论函数和莫 ...

  9. 【组合数学】生成函数 ( 使用生成函数求解多重集 r 组合数 )

    文章目录 一.使用生成函数求解多重集 r 组合数 二.使用生成函数求解多重集 r 组合数 示例 参考博客 : [组合数学]生成函数 简要介绍 ( 生成函数定义 | 牛顿二项式系数 | 常用的生成函数 ...

最新文章

  1. adodb.RecordSet的属性和方法
  2. linux安装vi 插件,Ubuntu上Vim安装NERDTree插件的详细操作步骤
  3. 信息化及信息化的五个层次
  4. oracle正则表达式截断,在oracle中使用正则表达式截取字符串
  5. ajax传递复杂参数
  6. 3.4.1 计算机网络之流量控制(停止-等待协议、滑动窗口、后退N帧协议GBN、选择重传协议SR)、滑动窗口、可靠传输机制
  7. SSH(Struts2+Hibernate+Spring)开发策略
  8. DRF (Django REST framework) 框架介绍(3)
  9. 小米 华为都要造车?.NET高薪潮来了!(附招聘链接)
  10. 百度地图iOS API
  11. python新手难点_初学两天python的操作难点总结
  12. 3 HTMLJS等前端知识系列之javascript的基础
  13. 如何将自定义消息添加到Mac锁屏
  14. 机器学习- 吴恩达Andrew Ng Week8 知识总结 Clustering
  15. Tomcat8安装及配置详解
  16. 【电商】电商后台设计—电商产品的用户体系
  17. 2017 4 自考java_自考00831英语语法2017年4月真题及答案【解析版】
  18. df pd 属性_pd.DataFrame()函数解析
  19. 【谷粒商城】阿里云oss文件上传(P61)
  20. 【数据结构】稀疏数组

热门文章

  1. Spark入门必读:核心概念介绍及常用RDD操作
  2. 榜单:全球 35 位 35 岁以下科技创新青年
  3. 分析一天1000万北京地铁客流,我们发现...
  4. 重磅!阿里首次全面公开展示AI布局(附布局图/成绩单/六产业详解)
  5. 学妹问我,并发问题的根源到底是什么?
  6. Dubbo的设计理念原来就藏在这三张图中
  7. Jack Dorsey二度卸任推特CEO,原CTO接棒,立即生效!
  8. Split-Bregman迭代方式
  9. 让自己开发的Web应用程序与SharePoint共存
  10. 2 HTML中的body和它的默认样式