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

一、定义及有用的性质

排列数:从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. Spring实战Day1

    为什么要学习使用Spring ------为了全方面简化Java开发 如何简化开发呢? 1.基于POJO[简单老式Java对象(Plain Old Java object)]的轻量级和最小侵入性编程, ...

  2. linux signal 列表

    Linux 信号表   Linux支持POSIX标准信号和实时信号.下面给出Linux Signal的简表,详细细节可以查看man 7 signal. 默认动作的含义如下: Term    终止进程 ...

  3. Linux终端Shell下的常用快捷键收集

    删除 [Ctrl]+[D]删除光标所在位置上的字符相当于VIM里x或者dl [Ctrl]+[H]删除光标所在位置前的字符相当于VIM里hx或者dh [Ctrl]+[K]删除光标后面所有字符相当于VIM ...

  4. CSS布局之BFC和IFC

    本文为原创,转载请注明出处: cnzt       文章:cnzt-p http://www.cnblogs.com/zt-blog/p/6708358.html <这是一篇css2-3的布局规 ...

  5. 巧用Drawable 实现Android UI 元素间距效果

    源文地址: 巧用Drawable 实现Android UI 元素间距效果 在大部分的移动UI或者Web UI都是基于网格概念而设计的.这种网格一般都是有一些对其的方块组成,然后它们组合成为一个块.使用 ...

  6. 关于rman duplicate 一些比較重要的知识点--系列三

    FYI: http://docs.oracle.com/cd/E11882_01/backup.112/e10643/rcmsynta020.htm#RCMRF126 rman duplicate d ...

  7. Office文档如何转换 PDF 转 DOC XLS

    1 使用Adobe Acrobat Pro,打开任意PDF都可以转换为XLSX格式(似乎没找到XLS)   2 如果你转换之后的东西无法打开,则先转换成DOC,然后再把DOC全选复制粘贴到XLS即可 ...

  8. Selenium系列之--01 简介【转】

    1.selenium 工具组件 1.1 selenium2,也称为selenium webdriver.webdriver原来是另一个自动化测试工具,后与selenium 合并了.webdriver直 ...

  9. getifaddrs

    getifaddrs 获取本地网络接口的信息.在路由器上可以用这个接口来获取wan/lan等接口当前的ip地址,广播地址等信息. #include <sys/types.h> #inclu ...

  10. 点滴记录——Ubuntu 14.04中Chrome浏览器标题栏出现中文乱码

    今天不知道在系统里装的哪个软件与Chrome浏览器所用的字体向冲突了,导致标题栏显示的中文都变成了乱码,其次收藏栏中的中文也变成了乱码.导致原有的收藏内容都无法辨认了.在网上搜索了一下,也有人遇到了相 ...