c语言分治法求众数重数_【OI学习笔记 | 数学】有趣的组合数

一、组合数的定义

定义
个元素中选出
个 (
),这
个元素叫做从
个元素中选出
个的一个组合;从
个元素中选出
个的组合的个数,叫做从
个元素中选出
个的
组合数,记作

:某省区从
年秋季起入学的新生,高考时不再分文理科,而是在语文、数学、英语这三科必选的基础上,再从物理、化学、生物、政治、历史、地理这
六科中任选三科。那么,一共有多少种选择组合?

解:列举可得,共有

种,即
.

二、组合数的计算

上面给出了组合数的一个应用。但是,求组合数真的一定要用一一列举吗?显然,我们有更好的方法——

性质一 对于组合数
,我们有:
. 其中,
称为
的阶乘,且
. 特别地,我们规定:
.

注:组合数公式是由排列数公式推导而来的,这里不再展开证明。

回到上面的问题,我们可以验证列举法是否正确。由于

,所以我们的列举是正确的.

三、组合数的一些神奇的性质——从杨辉三角谈起

800dccac31b8281e6735dabffc082650.png
此图片来自网络,侵删

杨辉三角是中国传统数学智慧的结晶,在今天还有它的作用。

我们来考虑杨辉三角的性质:

不妨将上图中的杨辉三角移成一个直角三角形,如下图:

如果从

开始编排行号/列号,记第
行第
列的元素为
,我们可以发现杨辉三角的一些规律:

04fc4643943727de00b3f0add4b3eb51.png

I.

II.

.

有了这两条递推关系,我们便可以计算出杨辉三角中任意一个位置的值了。

可这和组合数有什么关系呢?

观察第

行第
列的元素,竟然会发现
诶!

经过更多验证,我们可以得知,杨辉三角中第

行第
列的值就是
.

结合上面的两条递推关系,我们可以推出组合数的两条重要性质:

性质二
性质三

(证明略去。。。显然易证(并不))

对性质三,我们可以直观地理解:在若干个小球中,如果一个都不选或者全选,那显然只有一种选择。

继续观察这个三角形,还能发现组合数的“对称性”:

性质四

对性质四,我们又可以这样理解:在装有

个小球的袋子中,要选出
个来,有两种方法:一种是从袋子里拿出
个来,另一种是拿出
个来,在袋子里留下
个. 显然,这两种选法,得到的方案数是相同的.

再观察杨辉三角的每一行,我们尝试着求出每一行的和,又能发现两个性质:

性质五
性质六

最后,我们再来观察这样一组式子:

......

发现规律了吗?

对于

的展开式,我们可以发现:从左到右的每一项系数,就是杨辉三角形第
行从左到右的每一个数字!
定理

这个定理,我们称为二项式定理.

不难得到,

的展开式的第
项为:
,这称为二项式定理的通项公式.

四、关于组合数学的一些趣题

1. 洛谷P1313 计算系数(2011年NOIP提高组D2T1)

P1313 计算系数 - 洛谷​www.luogu.org

题目描述:

给定一个多项式

,请求出多项式展开后
项的系数.

输入格式:

共一行,包含

个整数,分别为
,每两个整数之间用一个空格隔开.

输出格式:

共一行,包含

个整数,表示所求的系数,这个系数可能很大,输出对
取模后的结果.

解:很显然,这题用二项式定理可以秒杀。

根据二项式定理可知,

(其实这个条件在题目的提示中已经给出了,但是我觉得这是多余的),则这一项可写成
.

与二项式定理对比通项可知:

.

如何快速地求出答案呢?

对于答案所需的两个幂运算,我们不难想到,使用快速幂即可(时间复杂度

);而要计算
的值,就得用到前面所提的
性质三(
了.

本题代码如下:

#include <cstdio>
#define MOD (10007)
#define int long long //很骚的宏定义
using namespace std;
int a,b,k,n,m,c[1001][1001];
int power(int a,int b){ //分治法求快速幂
    if(b==1) return a%MOD;
    if(b==0) return 1;
    int t=power(a,b/2)%MOD;
    if(b%2) return ((t*t)%MOD*a%MOD)%MOD;
    else return (t*t)%MOD;
}
void getC(){ //递推求解C[n][m]
    for(int i=0;i<=1000;i++){
        c[i][0]=1; //初始条件
        c[i][i]=1;
    }
    for(int i=2;i<=1000;i++)
        for(int j=1;j<=1000;j++)
            c[i][j]=(c[i-1][j]+c[i-1][j-1])%10007; //性质三,注意取模
}
signed main(){
    scanf("%lld %lld %lld %lld %lld",&a,&b,&k,&n,&m);
    getC();
    printf("%lld",(c[k][k-n]*((power(a,n)%MOD)*(power(b,k-n)%MOD))%MOD)%MOD);
    return 0;
}

2. 持续更新中……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值