声明:博主是个菜比,如果哪里写错了,请留言说明,谢谢,部分参考acdreamers大牛


定义 :

Lucas定理是用来求Cmn%p,p为素数的值。Lucas定理是用来求Cnm%p,p为素数的值。 Lucas定理是用来求 C_n^m \% p,p为素数的值。

推导


这个自行百度吧,和二项式有关,下面看下结论吧(我也不懂)

结论

已知:Cmn%pCnm%pC_n^m \%p

逆元可以使用费马大定理或者扩展欧几里得都行

经典例题:

[1] HDU 3037 Saving Beans

题意 :有n颗不同的树,每棵树的豆子无限多,问你有多少种方法可以保存不超过m个豆子(它们是相同的)。
分析:首先我们利用组合数中的隔板法来求出每个m的方案,然后求和即可

答案应该是 {n棵树取m个豆子} + {n棵树取m - 1} + {n棵树取m - 2} + …..+ {n棵树取0}
对于每个子问题我们利用隔板法来求解,比如第一个子问题 -> {n棵树取m个豆子}
我们把n棵树也当做豆子,然后在n + m个豆子中选出 m - 1个豆子来当做板子来分割,方案为Cm−1n+m−1Cn+m−1m−1C_{n+m-1}^{m-1}
同理,我们把若干子问题这样求出,答案依次为:
ans=C0n+C1n+1+⋅⋅⋅+Cm−2n+m−2+Cm−1n+m−1=Cmn+mans=Cn0+Cn+11+···+Cn+m−2m−2+Cn+m−1m−1=Cn+mmans = C_n^0 + C_{n +1}^1+···+C_{n+m-2}^{m-2} + C_{n+m-1}^{m-1} = C_{n +m}^m
上式是由Cmn=Cmn−1+Cm−1n−1Cnm=Cn−1m+Cn−1m−1C_n^m = C_{n - 1}^m +C_{n - 1} ^ {m - 1}推得

然后就利用Lucas来求即可

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>using namespace std;#define mod(x) ((x) % p)
typedef long long ll;
const int maxn = 1e5 + 10;ll fac[maxn + 10],rfac[maxn + 10];
ll n,m,p;ll qpow(ll a, ll b) {ll res = 1;while (b) {if (b & 1) res = mod(res * 1ll * a);a = mod(a * 1ll * a);b >>= 1;}return res;
}ll C(ll nn, ll mm) {ll up = 1, down = 1;for (int i = nn - mm + 1; i <= nn; i++) up = mod(up * 1ll * i);for (int i = 1; i <= mm; i++) down = mod(down * 1ll * i);return mod(up * qpow(down, p - 2));
}ll lucas(ll nn, ll mm) {if (mm == 0) return 1;return mod(lucas(nn / p, mm / p) * 1ll * C(nn % p, mm % p));
}int main() {int T; scanf("%d", &T);while (T--) {scanf("%lld%lld%lld", &n, &m, &p);printf("%lld\n", lucas(n + m, m));}return 0;
}

[2] HDU - 3944 DP?

题意: 已知在杨辉三角中,给你一个位置(简称CknCnkC_n^k),问你从(0,0)(n,k)经过的数字和最小,结果对P取模,每次可以往下走,或者往右下走。

分析 : 首先杨辉三角是左右对称的,如果所求的k > n / 2时,直接令k = n - k;即可,然后我们只考虑在一侧的情况即可,我们这样想如果k == 0时,我们一直往下走即可,假设n = 5,如果k = 1时,我们肯定优先往下走,然后到了n - 1的位置,再往右下走即可 简图如下 :

如果k == 2同理如下:

现在应该可以找到规律了,我们只需在当前位置往左上走,知道走到边界,然后再往上走即可
现在只需求和即可,我们利用Cmn=Cmn−1+Cm−1n−1Cnm=Cn−1m+Cn−1m−1C_n^m = C_{n - 1}^m +C_{n - 1} ^ {m - 1},可以得到
ans=Ckn+1+n−kans=Cn+1k+n−kans = C_{n +1} ^k + n - k
上式可以用数形结合来求出,这里请读者自行理解

这有个坑点,如果你用朴素的Lucas,会TLE,因为case特别多,我们需要做个预处理,题目上给了p给素数,范围只有1w,我们只需打出表即可,因为1e8的数组太大,我们需要把素数离散化一下,然后就可以了

参考代码

#include <bits/stdc++.h>
using namespace std;const int maxn = 1e4 + 7;typedef long long ll;ll f[maxn][1534];
bool isp[maxn];
ll p[maxn];
int len;
int mm[maxn];
ll P;
int idx;
#define mod(x) ((x) % P)void init() {isp[0] = isp[1] = true;for (int i = 2; i < maxn; i++) {if (!isp[i]) {p[len++] = i;for (int j = i + i; j < maxn; j += i) {isp[j] = true;}}}for (int i = 0; i < len; i++) mm[p[i]] = i;for (int i = 0; i < len; i++) {for (int j = 0; j < maxn; j++) {if(j == 0) f[j][i] = 1;else f[j][i] = (f[j - 1][i] * 1ll * j) % p[i];}}
}ll qpow(ll a, ll b) {ll res = 1;while (b) {if (b & 1) res = mod(res * 1ll * a);a = mod(a * 1ll * a);b >>= 1;}return res;
}ll C(ll n, ll m) {if (n < m) return 0;return mod(mod(f[n][idx] * qpow(f[m][idx], P - 2)) * 1ll*  qpow(f[n - m][idx], P - 2));
}ll lucas(ll n, ll m) {if(m == 0) return 1;return mod(lucas(n / P, m / P) * 1ll * C(n % P, m % P));
}int main() {ll n,m;int cnt = 1;init();while (~scanf("%lld%lld%lld", &n, &m, &P)) {idx = mm[P];if (m > n / 2) m = n - m;printf("Case #%d: %lld\n",cnt++, mod(lucas(n + 1,m) + n - m));}return 0;
}

[3] ZOJ - 3557 How Many Sets II

题意: 给你一个集合里面是{1,2,3···,n} 让你取m个元素,使得彼此不相邻,求方案数

分析: 这是经典的隔板法,首先最后我们肯定是取出m个元素,剩下n - m个元素,这n-m个元素有
n - m +1 个空,然后我们在尝试这放着m个元素,这样答案就是
ans=Cmn−m+1ans=Cn−m+1mans = C_{n - m + 1} ^ m
利用lucas计算即可

参考代码

#include <cstdio>
#include <algorithm>
#include <cstring>using namespace std;const int maxn = 1e5 + 10;
typedef long long ll;
ll p;
#define mod(x) ((x) % p)ll qpow(ll a, ll b) {ll res = 1;while (b) {if(b & 1) res = mod(res * 1ll * a);a = mod(a * 1ll * a);b >>= 1;}return res;
}ll c(ll n, ll m) {ll up = 1, down = 1;for (ll i = 1; i <= m; i++) down = mod(down * 1ll * i);for (ll i = n - m + 1; i <= n; i++) up = mod(up *1ll * i);return mod(up *qpow(down, p - 2));
}ll lucas(ll n, ll m) {if (m == 0) return 1;return mod(lucas(n / p, m / p) * c(n % p, m % p));}int main() {ll n,m;while (~scanf("%lld%lld%lld", &n, &m, &p)) {printf("%lld\n", lucas(n - m + 1, m));}return 0;
}

[4] HDU - 4349 Xiao Ming’s Hope

题意: 问你{C0n,C1n,⋅⋅⋅⋅,Cn−1n,CnnCn0,Cn1,····,Cnn−1,CnnC_n^0, C_n^1,····,C_n^{n - 1},C_n^n} 中有多少奇数

分析: 这里参考acdream的做法,甚是巧妙,
我们假设每个组合数都要对2取模,就变成了Lucas了,也是对n,m转化成了二进制后,我们发现
C00=1C00=1C_0^0 = 1 ··· C10=0C01=0 C_0^1 = 0 ··· C01=1C10=1 C_1^0 = 1 ···· C11=1C11=1C_1^1 = 1
我们将n转化成二进制以后,如果要是得Cmn%==0Cnm%==0C_n^m \% == 0,
n某一位上是0时,所对应的m只能为0
而当n某一位上是1时,所对应的m可以为0 也可以为1
所以我们只需统计n转化成二进制后1的个数即可

附 : 这里用到了__builtin,相关位运算,参考这里

参考代码

#include <bits/stdc++.h>
using namespace std;
int main () {int n;while (~scanf("%d", &n)) {printf("%d\n", 1 << (__builtin_popcount(n)));}return 0;
}

组合数——Lucas 基础学习整理【陆续更新】相关推荐

  1. java基础学习整理(一)

    java基础学习整理(一) lesson1: D0s命令: 1.回到根目录,>cd \ 2.复制命令行下的内容,右击标记所要复制的内容,这样就已经复制好了,右击粘贴就可以了. 3.查看,设置环境 ...

  2. Linux基础学习整理

    linux学习记录 下载地址 centos 下载地址: 网易镜像:http://mirrors.163.com/centos/6/isos/ 搜狐镜像:http://mirrors.sohu.com/ ...

  3. vue.js基础学习(数组更新)

    基础入门:vue.js 数组更新 1.vue.js 数组更新 通过索引值修改数组,this.list[6]=7: push():给数组末尾添加元素,this.list.push(7,8,9): pop ...

  4. Objective-C基础学习心得(更新ing)

    目录 IOS基础笔记 程序结构 输入和输出 @property 1 是什么? 2 创建存取器的两种方式 2.1 手动创建 2.2 使用@property创建 3 属性 3.1 原子性 3.2 存取器控 ...

  5. Java基础学习 Day01----持续更新

    关于java Java是高级开发语言, 支持跨平台 特点:封装.继承.多态 java使用 java环境安装:jdk1.8(本机安装到e盘 尽量不要安盘) 利用控制台操作java代码    在jdk目录 ...

  6. SqlServer数据库基础知识整理(不断更新~)

    1.SQL Server中@@ROWCOUNT返回受上一语句影响的行数,返回值类型为 int 整型. 如果行数大于 20 亿,则需要使用 ROWCOUNT_BIG. @@ROWCOUNT和@@ERRO ...

  7. JAVA基础学习日记-----持续更新

    第一节,计算 1. System.out.println() // 输出带有回车System.out.print() // 不带有回车 2. +号可以连接两个字符串 3. 有几个in.nextInt( ...

  8. laravel 框架基础 学习整理

    一. Laravel 数据库迁移 创建迁移文件(在database/migrations目录) php artian make:migration create_table_articles --cr ...

  9. es2015(es6)基础知识整理(更新中...)

    1.let let可以声明块级作用域变量 1 'use strict'; 2 3 if (true) { 4 let app = 'apple'; 5 } 6 7 console.log(app); ...

最新文章

  1. Java基础之Comparable接口和Comparator接口的比较
  2. 微软正式发布Windows 10 2020年10月更新
  3. 编写windows 控件需要注意的几个标签属性(Attribute)
  4. 关于汽车领域的知识图谱实战入门
  5. 阿里云 mysql 超时_mysql数据库超时
  6. python迅雷_迅雷下载链接解析器。
  7. AndEngine引擎之SmoothCamera 平滑摄像机
  8. 作者:牛海波,男,中国国防科技信息中心工程师。
  9. chrome谷歌浏览器安装教程 20200701
  10. protobuf windows lib链接库生成
  11. 写给考完SDOI2016R2D1的自己
  12. python100例图案_python100例 21-30
  13. 借助终端软件,有效统一移动互联网和物联网
  14. 【整理】linux学习笔记整理8
  15. 利用群体遗传数据估计基因组上重组率
  16. meta camp+21春季PAT乙级反思
  17. python| requests 访问 https网站
  18. 基于Token的WEB后台认证机制
  19. 【ps功能精通】4.简单背景图片抠图
  20. 浅谈Openstack网络原理(openstack无法上网?)

热门文章

  1. 微信小程序实现各种特效实例
  2. wim10系统怎么装java_w10系统怎么安装java开发环境|w10安装java开发环境的方法
  3. 计算机软件为什么要升级呢,到底电脑要不要升级呢,看完你就懂了
  4. 使用elementui踩坑(实则手贱),组件库显示不出来,需要点击多次才会出现的bug
  5. 视频教程-79节PS入门基础视频教程-Photoshop
  6. onethink后台使用上传驱动时,文件上传失败
  7. Wallpaper Engine免费版,Wallpaper壁纸引擎,Wallpaper Engine离线版更新至2.2.18版本,23年2月新版,解决导入壁纸时提示需要更新的问题,附一套全新壁纸
  8. 什么是次世代?零基础学习次世代全解
  9. 亚马逊云计算服务有什么特色?
  10. 古月居ROS入门21讲-基础概述