[笔记]ACM笔记 - 组合数
一、高中数学公式复习
Cmn=n!m!(n−m)!
Cmn=Cn−mn=Cmn−1+Cm−1n−1
C0n+C1n+C2n+...+Cnn=∑ni=0Cin=2n
C0n+C2n+C4n+...=C1n+C3n+C5n+...=2n−1
Cmn+Cmn+1+Cmn+2+...+Cmn+m=∑mi=0Cmn+i=Cm+1n+m+1
kCkn=nCk−1n−1, Cknk+1=Ck+1n+1n+1 (好吧这个没学过但是既然看到了就一并抄过来了)
二、快速求组合数取模C(n, m)%p
当n和p大小不同时方法有不同。
1. n很小,p随意,p不需要为素数
1) 原理
使用杨辉三角:Cmn%p=(Cm−1n−1+Cmn−1)%p
组合数C(n, m)其实就是杨辉三角第n行第m列的值(下标从0开始算的话)。每一行的各个值都是迭代上一行的结果。那么用二维数组打个表即可,for里套个for。
2) 我的模板
typedef long long lld;
const int maxn = 1000+10;
lld C_arr[maxn+10][maxn+10];
void C_init(int n, int pr) {
for (int i = 0; i <= n; i++) {
C_arr[i][0] = C_arr[i][i] = 1;
for (int j = 1; j < i; j++)
C_arr[i][j] = (C_arr[i - 1][j - 1] + C_arr[i - 1][j]) % pr;
}
}
lld C(int n, int m) {
return C_arr[n][m];
}
2. n相对小(方便打表),p可以很大,p要求为素数
1) 原理
仅使用费马小定理: 若p是质数,且a,p互质,那么 a的(p-1)次方除以p的余数恒等于1, 即a^(p-1) ≡ 1 (mod p),所以a^(p-2) ≡ 1/a (mod p)。所以a的逆元为a^(p-2)。于是将n!m!(n−m)! 中的除法全变成了乘法:
得到公式:Cmn%p=((n!)%p∗[(n−m)!]p−2%p∗(m!)p−2%p)%p
2) 我的模板
lld pow_mod(lld a, lld b, const int &pr)
{
lld ans = 1;
while (b) {
if (b & 1) ans = ans * a % pr;
b >>= 1;
a = a * a % pr;
}
return ans;
}
lld C(int n, int m)
{
return fac(n) % p * pow_mod(fac(n - m), p - 2, p) * pow_mod(fac(m), p - 2, p);
}
可以看到这里最麻烦的是求阶乘fac(n),如果n不大的话打表是极好的。n较大的话使用以下公式递归求得:
n!=n!(n2)!n2)!∗[(n2)!]2=Cn/2n∗[(n2)!]2
具体以后再写一篇求阶乘。
lld C_small(lld n, lld m, const int &pr)
{
lld ans = 1;
for (int i = 1; i <= m; i++)
{
lld a = (n - m + i) % pr;
lld b = i % pr;
ans = ans * (a * pow_mod(b, pr - 2, pr) % pr) % pr; //Fermat Theory
}
return ans;
}
这是不打表的版本(其实就是没打表而已,没什么区别)。
3. n很大时要求p较小(p<10^5),p要求为素数
1) 原理
使用Lucas定理:Cmn%p=(Cm%pn%pCm/pn/p)%p
为什么要求p挺小,由公式就可以看出,p太大了的话Cm%pn%p也依然很大。Lucas定理用到了费马小定理,要求p为素数。对于每个Cm/pn/p,递归调用Lucas定理。可以看见n被p取模后很容易就变小了,所以要求p较小。
定理证明:网上看到的大神的博客
2) 我的模板
typedef long long lld;
lld pow_mod(lld a, lld b, const int &pr)
{
lld ans = 1;
while (b) {
if (b & 1) ans = ans * a % pr;
b >>= 1;
a = a * a % pr;
}
return ans;
}
lld C_small(lld n, lld m, const int &pr)
{
lld ans = 1;
for (int i = 1; i <= m; i++)
{
lld a = (n - m + i) % pr;
lld b = i % pr;
ans = ans * (a * pow_mod(b, pr - 2, pr) % pr) % pr; //Fermat Theory
}
return ans;
}
lld C(lld n, lld m, const int &pr) // Lucas's theorem
{
if (m == 0 || m == n) return 1;
return C_small(n % pr, m % pr, pr) * C(n / pr, m / pr, pr) % pr;
}
C_small就是用求逆元求解,像法二一样做打表也是极好的。
如果n不大,p很大,用一下Lucas定理后也就相当于执行了法二,所以以后直接用Lucas即可。
三、Vandermonde恒等式
范德蒙(Vandermonde)恒等式:
其中k肯定得小于等于min(n,m)。
理解:从n个黑球、m个白球里找k个球有多少方式。
当k=min(n,m)时,这里假设m<n,那就是k=m时,可以变个形:
那意义就是n个黑球和m白个球中各找0个、1个、2个……m个对应颜色的球,一共有多少方法。
例题链接:Codeforces 785D - Anton and School - 2
[笔记]ACM笔记 - 组合数的更多相关文章
- [笔记]ACM笔记 - 利用FFT求卷积(求多项式乘法)
卷积 给定向量:, 向量和: 数量积(内积.点积): 卷积:,其中 例如: 卷积的最典型的应用就是多项式乘法(多项式乘法就是求卷积).以下就用多项式乘法来描述.举例卷积与DFT. 关于多项式 对于多项 ...
- [笔记]ACM笔记 - 自用模板
长期更新. 快速幂 lld pow_mod(lld a, lld b, const int &pr) { lld ans = 1; while (b) { if (b & 1) ans ...
- [笔记]ACM笔记 - 排序小技巧
Description 一个数组,要求先对前n个数字排序(以方便后续操作):又要求对前n+i个数字排序:又要求对前n+j - 前n+k个数字排序(i.j.k的大小远小于n,且i.j.k间没有大小关系) ...
- ACM笔记
写给自己看,纯属打发时间... Sacnf的返回值是成功赋值的变量个数 for(int i=0; i<100; i++) 在C++标准中指出for循环条件中定义的变量,作用域仅限于循环内部 ...
- HTML+CSS笔记 CSS笔记集合
HTML+CSS笔记 表格,超链接,图片,表单 涉及内容:表格,超链接,图片,表单 HTML+CSS笔记 CSS入门 涉及内容:简介,优势,语法说明,代码注释,CSS样式位置,不同样式优先级,选择器, ...
- 用html和css轻松实现康奈尔笔记(5R笔记)模板
缘起 人家都说康奈尔笔记法,很好用呢,能抵抗遗忘曲线,让你的笔记事半功倍,有兴趣的同学自行百度哈. 网上有很多现成的模板,下载下来之后吧,看着好像在上面写英文可能更方便一点,行距很小,而且还有网址在上 ...
- 【MarkMark学习笔记学习笔记】javascript/js 学习笔记
1.0, 概述.JavaScript是ECMAScript的实现之一 2.0,在HTML中使用JavaScript. 2.1 3.0,基本概念 3.1,ECMAScript中的一切(变量,函数名,操作 ...
- 《MarkMark学习笔记学习笔记》html学习笔记
iframe里有一个srcdoc属性,很有用! window.location.href=document.referrer//可以实现返回上一级页面并刷新 HTML5权威指南©®,比较老的书了,有些 ...
- object - c 语言基础 进阶笔记 随笔笔记
重点知识Engadget(瘾科技)StackOverFlow(栈溢出)Code4Apprespon魏先宇的程序人生第一周快捷键: Alt+上方向键 跳到最上面 Alt+下方向键 跳到最下面 ...
随机推荐
- Yii2中rules验证规则
required : 必须值验证属性 [['字段名'],required,'requiredValue'=>'必填值','message'=>'提示信息']; #说明:CRequiredV ...
- mysq常用l性能分析方法
orzdba查看读写./orzdba.pl --mysql -S /data/mysql30001/mysql.sock 语句查看读写命令数量,以及数据库TPS,传输的大小 查看processlist ...
- 多线程CountDownLatch和Join
如果现在有五个线程A.B.C.D.E,请问如何用E线程用于统计A.B.C.D四个线程的结果? 题意需要用E线程统计A.B.C.D四个线程,也就是说E线程必须要等到前面四个线程运行结束之后才能执行.那么 ...
- 重温Javascript(一)
工作中要用到JavaScript,一组复习笔记. 一些看法 1. 想想JavaScript目前最常用的宿主环境,浏览器或者服务端V8,都是单线程,所以不用过多的考虑并发的问题,如果是协程来实现异步的方 ...
- Vijos1327回文词【动态规划】
回文词 回文词是一种对称的字符串--也就是说,一个回文词,从左到右读和从右到左读得到的 结果是一样的.任意给定一个字符串,通过插入若干字符,都可以变成一个回文词.你的任务是写 一个程序,求出将给定字符 ...
- Java并发编程:JDK中的阻塞队列
上次我们讲了一些常用的4个阻塞队列,但是在JDK中还提供了其他的一些阻塞队列.这篇文章将全面介绍一下JDK中的所有阻塞队列,并比较他们的区别. JDK7提供了7个阻塞队列.分别是 ArrayBlock ...
- 转接IC整理汇总 转接芯片大全
转接口IC大全,信号转换大全EDP输出信号NCS8801 LVDS转EDP.RGB转EDP 封装QFN56 最大分辨率2560*1600用于手机.平板.转接板.液晶驱动板.广告机.可视门铃等等控制器到 ...
- 为Jquery EasyUI 组件加上“清除”功能
1.背景 在使用 EasyUI 各表单组件时,尤其是使用 ComboBox(下拉列表框).DateBox(日期输入框).DateTimeBox(日期时间输入框)这三个组件时,经常有这样的需求,下拉框或 ...
- AFNetworking 用法详解
之前一直使用ASIHttpRequest 做网络请求 ,后来新公司用AFNetWorking ,经过一段时间学习总结一下二者的优缺点: 1.AFNetWorking的优缺点 优点: 1.维护和使用者比 ...
- 149_best-time-to-buy-and-sell-stock
/*@Copyright:LintCode@Author: Monster__li@Problem: http://www.lintcode.com/problem/best-time-to-b ...