先来了解几个概念:排列数,组合数。

一、定义及有用的性质

排列数:从n个不同元素中依次取出m个元素排成一列的方案数。P(n,m)=n!/(n-m)!

组合数:从n个不同元素中依次取出m个元素形成一个集合的方案数。(注意,集合满足无序性,这是和排列数的区别)。C(n,m)=n!/m!(n-m)!

组合数性质

  性质1 C(n,m)= C(n,n-m)

  性质2 C(n,m)=C(n-1,m-1)+C(n-1,m)

  性质3 C(n,0)+C(n,1)+C(n,2)+...+C(n,n)=2^n(道出组合数与杨辉三角间的联、系)

二、组合数球阀

① 递推 复杂度为n²

  c[i][j]=c[i-1][j]+c[i-1][j-1]

但是要注意要命的初始化--

丢一段代码跑。

② 预处理阶乘+逆元 复杂度为nlogn

首先我们应该知道,除以一个数等于乘上这个数的逆元,那么我们就可以直接(生猛 地利用原始带有阶乘的公式,分母我们处理逆元。这里用到的是最简单的费马小定理方法,一个数x在膜p意义下的逆元等于x^(p-2)

丢一段代码跑。这个方法的使用条件是p为素数

 #include<cstdio>
#include<algorithm> using namespace std;
typedef long long ll;
const int p=1e9+; ll n,k,x;
ll ans=; ll ksm(ll a,ll b)
{
ll tmp=;
while(b)
{
if(b&) tmp=tmp*a%p;
b>>=;
a=a*a%p;
}
return tmp;
} int main()
{
//求C(n,k)
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++) ans=ans*i%p;
for(int i=;i<=k;i++) ans=ans*ksm(i,p-)%p;
for(int i=;i<=n-k;i++) ans=ans*ksm(i,p-)%p;
printf("%lld",ans);
return ;
}

*Update 费马小定理有的时候可能会复杂度爆炸 这里介绍一种exgcd求逆元的方法

 ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==)
{
x=;
y=;
return a;
}
int gu=exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
return gu; } ll niyuan(ll hu)
{
x=,y=;
ll tmp=exgcd(hu,p,x,y);
return (x+p)%p;
} ll C(ll k,ll m)
{
ll up=fac[k]%p;
ll down=fac[m]%p*fac[k-m]%p;
ll ans=up*niyuan(down)%p;
return ans;
}

③ 分解质因数 复杂度为nlogn

前导芝士:算术分解定理。

我们把分子分母都进行分解质因数,把整个分子分母对应的质因数的指数相减(消去)

丢一段代码跑。

 #include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
int n,m;
int p;
int i,j;
int tot;
int prim[],cnt[];
bool flag[]; void fj(int a,int k)//分解质因数 k=1/-1
{//k==1时为分子操作 质因子数++
//k==-1时为分母操作 质因子数--
int x=a;
for (int i=;i<=tot;i++)
{
if (x%prim[i]==)
{
while (x%prim[i]==) x/=prim[i],cnt[prim[i]]+=k;
}
if (x==) break;
if (prim[i]*prim[i]>n) break;
}
if (x>) cnt[x]+=k;
} int Pow(int x,int a)
{
int ans=; int j=;
while (j<=a)
{
if (j&a) ans=((LL)ans*(LL)x)%p;
j<<=;
x=((LL)x*(LL)x)%p;
}
return ans;
} int main()
{
scanf("%d%d%d",&n,&m,&p);
//筛素数
for (i=; i<=n; i++)
{
if (!flag[i]) prim[++tot]=i;
for (j=; j<=tot; j++)
{
if (prim[j]*i>n) break;
flag[prim[j]*i]=;
if (i%prim[j]==) break;
}
}
//printf("/////");
int a=m; int b=(n-m);
int c=max(a,b);
//一定有一部分会自己消去(上下完全相同)
for (i=c+; i<=n; i++)
{//分子操作
fj(i,);
}
//分母操作
for (i=;i<=min(a,b);i++) fj(i,-);
int ans=;
for (i=; i<=n; i++)
{
if (cnt[i]>) ans=((LL)ans*Pow(i,cnt[i]))%p;
}
printf("%d\n",ans);
return ;
}

组合数的几种球阀 By cellur925的更多相关文章

  1. 浅谈Floyd的三种用法 By cellur925

    Floyd大家可能第一时间想到的是他求多源最短路的n³算法.其实它还有另外两种算法的嘛qwq.写一发总结好了qwq. 一.多源最短路 放段代码跑,注意枚举顺序,用邻接矩阵存图.本质是一种动规. 复杂度 ...

  2. Adjacent Bit Counts(01组合数)

    Adjacent Bit Counts 4557 Adjacent Bit CountsFor a string of n bits x 1 , x 2 , x 3 ,..., x n , the a ...

  3. [数]数学系列预习->补水题ver.

    ---恢复内容开始--- 话说要学反演了,contest一题都搞不定,整理题目暂且搁置,数学笨蛋来学一下数学_(:з」∠)_ ---恢复内容结束--- 是的,预习看了半天教学,没有整理,做题又都不会, ...

  4. java小程序(课堂作业02)

    1,三种方法计算组合数 ①设计思路:第一种方法就是通过阶乘公式然后运用公式计算出组合数,第二种通过公式推导出cnk=n/(n-k)cnk-1,然后然后从ckk 开始运算到cnk,第三种方法就是通过递归 ...

  5. 一种递推组合数前缀和的Trick

    记录一下一种推组合数前缀和的方法 Trick 设\(\sum_{i = 0}^m C_n^i = S(n, m)\) \(S\)是可以递推的 \(S(n, m + 1) = S(n, m) + C_{ ...

  6. 1-求组合数(c(n, m))的几种方法

    1.求C(n, m) 动态规划(递归+记忆数组) 递推关系为:C(n, m) = C(n-1, m) + C(n - 1, m - 1),C(n, m)表示为从n个数中选出m个出来,可以基于最后一个元 ...

  7. 组合数C(n,m)的四种求解方法

    转自:文章 1.暴力求解 C(n,m)=n*(n-1)*...*(n-m+1)/m!,(n<=15): int CF(int n,int m) { ,i,j; ;i--) ans*=i; ;i- ...

  8. LCM性质 + 组合数 - HDU 5407 CRB and Candies

    CRB and Candies Problem's Link Mean: 给定一个数n,求LCM(C(n,0),C(n,1),C(n,2)...C(n,n))的值,(n<=1e6). analy ...

  9. 计算一维组合数的java实现

    背景很简单,就是从给定的m个不同的元素中选出n个,输出所有的组合情况! 例如:从1到m的自然数中,选择n(n<=m)个数,有多少种选择的组合,将其输出! 本方案的代码实现逻辑是比较成熟的方案: ...

随机推荐

  1. [洛谷U22156]未曾届到游览(矩阵树定理)

    题目背景 又到了某任*堂开关中学一年一度的自主招生考试的时间了,在考试完后许多家长决定带着自己的孩子参观一下这所距千年名校还有890周年的百年学校: 题目描述 这所学校的布局非常奇怪,是一个由N 个点 ...

  2. 11-Js类和对象

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. Python导入模块的几种姿势

    中文翻译:http://codingpy.com/article/python-import-101/ 英文原文:http://www.blog.pythonlibrary.org/2016/03/0 ...

  4. 类的相互依赖导致StackOverflowError

    public class SchoolServiceImpl { private static SchoolServiceImpl instance = new SchoolServiceImpl() ...

  5. Nerv --- React IE8 兼容方案

    创建项目 创建一个目录,使用npm快速初始化 $ mkdir my-project && npm init -y 安装依赖 安装webpack以及babel $ npm install ...

  6. 数据库分表和分库的原理及基于thinkPHP的实现方法

    为什么要分表,分库: 当我们的数据表数据量,訪问量非常大.或者是使用频繁的时候,一个数据表已经不能承受如此大的数据訪问和存储,所以,为了减轻数据库的负担,加快数据的存储,就须要将一张表分成多张,及将一 ...

  7. MySQL基础笔记(三) 复杂查询

    所谓复杂查询,指涉及多个表.具有嵌套等复杂结构的查询.这里简要介绍典型的几种复杂查询格式. 一.连接查询 连接是区别关系与非关系系统的最重要的标志.通过连接运算符可以实现多个表查询.连接查询主要包括内 ...

  8. 软件project

    Problem Description Merlin的软件project老师Max布置了开发一个软件的大作业.因为这是一个大型软件.所以单靠Merlin一个人不可能在预订的时间内做完,必须与其它人合作 ...

  9. 竞赛中经常使用的C++写法

    首先是构造函数,重载 #include <iostream> #include <cstdio> #include <cstring> #include <s ...

  10. 深度学习笔记之使用Faster-Rcnn进行目标检测 (实践篇)

    实验 我使用的代码是Python版本的Faster Rcnn,官方也有Matlab版本的,链接如下: py-faster-rcnn(python) faster-rcnn(matlab) 环境配置 按 ...