今天在刷OJ的时候,刷到了这样一道题

题目描述:
NEUQ-AcmClub养了许多鸽子,有一天鸽子王想给鸽子们排排班,现在有n只鸽子,每天需要m只鸽子值班,问有多少种值班组合。由于答案可能较大,我们把答案对一个素数p取模输入:
输入三个整数 m,n, p m,n<10^18,p <=10^5输出:
输出一个整数样例输入:
2 5 11
样例输出
10

这一看不就是个水题直接求组合数求余嘛,打表直接提交。

memset(c,0,sizeof(c));c[0][0] = 1;for(int i = 1; i <= 1000; i ++){for(int j = 0; j <= i; j ++)if(j == 0 || j == i) c[i][j] = 1;else c[i][j] = c[i-1][j-1] + c[i-1][j];}

成功WA,返回来一看,m,n的数据范围直接给到了int_64,思考一番,不会。果断去百度了一下,才发现原来有一个定理——卢卡斯定理(用来特意解决这类问题),可能是我比较菜,费了好大劲才理解网上的讲解,于是打算自己写一篇我认为相对来说易于理解的blog。
(由于是主要学习算法,所以博客在分析算法的为主线的情况下去理解各种定理)

首先,我们目的是要求C(n,m)%p,而卢卡斯定理就是用来解决组合数求余的问题,首先来看一下卢卡斯定理的定义

通俗来讲就是
前提:
a,b可以表示成

且p为素数

结论:

前提对于任意a,b和素数p一定成立,因为最简形式为a = a0,如果a或b小于p,则问题退化为求c(a,b)

至于证明,可以简单了解一下,涉及到的数学知识较多,并不是算法的重点,所以不再过多介绍
下图参考冯志刚《初等数论》第37页。

有了卢卡斯定理,我们的求解过程就变得简单了。

Lucas:return 求组合数(a % p, b % p) * 卢卡斯函数(a / p, b / p);

那么如何来理解上面的代码呢,首先看求组合数这个函数,传入的是(a%p,b%p)这两个参数,那么正好对应上述公式里的a0和b0,然后将a,b分别除于p相当于以下过程

所以每次相当于将上述公式的ai传进去了,直到a被除到0为止

解决了这个问题,看似已经解决了求组合数的问题,但是还有很重要的一点,就是求余,在int_64的数据范围下,不采用同余法,是非常容易让数据直接爆掉的,而求组合数公式为

C(n, m) mod p = n!/(m!(n - m)!) mod p

不巧,恰好用到了除法,不能使用同余定理,但是不使用的话又会爆数据,那怎么办呢?这时候就要引入一个新的定理和新的概念了。新的概念就是乘法逆元。
乘法逆元:

a * b≡ 1 mod c 若 (a*b)%c ≡ 1成立,则称a关于模c的乘法逆元为b,反之同样成立。

这样有什么用处呢?引入乘法逆元之后 若 a*b≡1mod c 则 (d / a)%c ≡(d * b)%c (逆元就相当于倒数 a除以b就相当于a乘b分之一) 这时候求组合数的表达式就可以转化为乘法,也就可以使用同余定理了。

知道逆元的存在,所有问题都迎刃而解,但是应该怎么求逆元呢?
这时候在引入一个新的定理——费马小定理
当p为质数时 a^(p-1) ≡ 1 (mod p)
将等式变形一下 a * a^(p-2) ≡ 1 (mod p)所以 a 关于模p的逆元为a ^(p-2)
此时所有问题都影刃而解,可以码代码了,但是开头提到的扩展欧几里得和这些又有什么关系呢?
扩展欧几里得是另一种求逆元的方法,ax≡1 (mod p)可以变形为ax-yp=1 在a,b已知情况下,可以用扩展欧几里得算法算出x,求出a的逆元。(求解组合数时仍采用费马小定理,个人认为比较容易理解)
这里给出扩展欧几里得算法:

   void gcd(int a,int b,int &d,int &x,int &y){if(!b){ d=a;x=1;y=0 }else{ gcd(b,a%b,d,y,x); y-= x*(a/b); }}

有兴趣可以自己了解一下
那么继续回到主题,所有的准备工作已经就绪,接下来具体实现的代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;ll quick_mod(ll a,ll b,ll m)//快速幂求a^b
{ll ans = 1;while(b!=0){if(b&1!=0) ans = ((ans % m) * (a % m)) % m;a = ((a % m) * (a % m)) % m;b >>= 1;}return ans;
}
ll comp(ll a,ll b,ll m) //求组合数
{if(a<b) return 0;if(a==b) return 1;if(b>a-b) b=a-b;ll ans=1,ca=1,cb=1;for(int i=0;i<b;i++){ca=ca*(a-i)%m;cb=cb*(b-i)%m;}ans=ca * quick_mod(cb,m-2,m) % m; //quick_mod(cb,m-2,m)费马小定理求逆元return ans;
}ll lucas(ll a,ll b,ll m)//卢卡斯定理
{return a && b ? (lucas(a/m,b/m,m) % m * comp(a%m,b%m,m) ) % m : 1;
}int main()
{ll a,b,m;cin>>b>>a>>m;cout<<lucas(a,b,m)<<endl;
}

此时算法就写完了,交一发

完美AC,开心的去吃饭

卢卡斯定理求组合数(逆元+费马小定理+扩展欧几里得)相关推荐

  1. 子段乘积(逆元费马小定理)+线段树做法

    题解:一开始做这个题的时候想过尺取法,但是因为没有逆元的知识,不知道该如何不断删除左端元素.其实这题并不难想,设l,r为两端开始都置为1,当长度小于k的时候不断乘右端元素并取余,当长度等于k时删除左端 ...

  2. 逆元+费马小定理+扩展欧几里得

    逆元:(即是逆元素)逆元素是指一个可以取消另一给定元素运算的元素. 在一个代数系统(S,*)中,存在单位元素e,如果对S内的元素a存在a^-1 * a = e,则将 a^-1称为a 的左逆元. 同理若 ...

  3. 除法取模与逆元/费马小定理

    对于正整数和,如果有,那么把这个同余方程中的最小正整数解叫做模的逆元. 逆元一般用扩展欧几里得算法来求得,如果为素数,那么还可以根据费马小定理得到逆元为.(都要求a和m互质) 推导过程如下(摘自Acd ...

  4. 计算系数(二项式定理逆元费马小定理)

    给定一个多项式(ax+by)^k,请求出多项式展开后(x^n)*(y^m)项的系数. 输入格式 共一行,包含 5 个整数,分别为 a,b,k,n,m,每两个整数之间用一个空格隔开. 输出格式 输出共 ...

  5. 关于素数常用结论--威尔逊定理、欧拉定理、费马小定理、米勒罗宾算法

    再需要判定的数比较大时,用枚举法肯定不行的,但目前数学界也没有任何一种又快又准确的判定素数的方法,并且也证明了素数不存在任何一种通项表达式.但作为初等数论中最大的一部分内容,数学家们对素数性质进行了大 ...

  6. 7. 数论四大定理(威尔逊定理、欧拉定理、费马小定理、孙子定理)

    一.准备工作 点击查看数论基础知识 二.威尔逊定理 威尔逊定理给出了判定一个自然数是否为素数的充分必要条件.但是由于阶乘是呈爆炸增长的,其结论对于实际操作意义不大. 1. 定理及其变形 当且仅当p为素 ...

  7. 数论四大定理(欧拉定理、费马小定理、中国剩余定理、威尔逊定理)

    前置知识 同余 假设 a,ba,ba,b 都是整数,如果 nnn 是一个正整数,且存在整数 kkk 使得 a−b=k×na−b=k \times na−b=k×n,则称 a,ba,ba,b 模 nnn ...

  8. 小结:数论四大定理(威尔逊定理+欧拉定理+中国剩余定理+费马小定理)

    前置知识: 模运算消去律:ac ≡ bc (mod p) → a ≡ b (mod p/gcd(c,p) ) 威尔逊定理: 当且仅当p为素数时,( p -1 )! ≡ -1 ( mod p ) 当且仅 ...

  9. jzoj4229-学习神技【逆元,费马小定理】

    正题 题目大意 求 (∑i=1na∗qi)mod(109+7)(\sum_{i=1}^na*q^i)\ mod\ (10^9+7)(i=1∑n​a∗qi) mod (109+7) 解题思路 题目里都给 ...

  10. 取模除法(逆元)(费马小定理)(线性求逆元)

    文章目录 引言 逆元 费马小定理 内容 应用 证明 线性求逆元 thanks for reading! 引言 我们做题时经常会由于答案过大,被要求使答案对一个质数取模 我们都知道,加和乘对取模是没有影 ...

最新文章

  1. 理论计算机科学中最令人困惑的谜题之一被解开
  2. 全球首个AI女主播上岗了!太惊艳了!
  3. kali linux有线连接不见网络图标不见(解决方案)
  4. 剪板机自动上下料_机器人联轴器,用于机器人自动化上下料
  5. 第一课[编辑器设置-VC++6.0]
  6. 【AI】(收藏)从 A-Z 全面盘点人工智能专业术语梳理!
  7. 宁德时代811电芯初现真容 搭配宝马X1混动汽车能量密度提升近6成
  8. sqlalchemy 聚合
  9. js图片 area 颜色_JS提取图片的主体颜色
  10. php异步学习(2)
  11. fx5u模拟量如何读取_最全三菱FX5U系列PLC视频
  12. UEFI 文件类型.efi
  13. 基于pyswarm库实现粒子群优化算法求解带约束的优化问题
  14. [c#源码分享]TCP通信中的大文件传送
  15. Word里面怎么才能输入平方
  16. [日常训练] 联络网
  17. VSCode PlatformIO IDE 下开发ESP32遇到的问题
  18. android文字转语音文件格式,Android文字转语音
  19. Python编程:从入门到实践(基础知识)
  20. 计算机经常突然死机重启,家里电脑最近经常会出现重启死机的现象是什么原因?...

热门文章

  1. c语言.jpg图片转成数组_如何把PDF图片转成JPG?两个方法快速搞定PDF转图片!
  2. 转载: DEV控件:gridControl常用属性设置_人生一世 草木一秋_百度空间
  3. Qt5.12.6 + VS2019添加图片资源文件
  4. Echart3绘制世界地图连线中国城市
  5. java mc和java jdk_JDK、JRE、JVM三者间的关系
  6. 「电创云」:「空间优造」与「绿多多」「绿点」绿色社区
  7. Java实现 LeetCode 319 灯泡开关
  8. Android之Edittext禁止输入表情符号(雷惊风)
  9. Docer容器的介绍(一)-------Docker基本概念和框架
  10. 服务器appcrash的问题怎么修复,APPCRASH问题如何解决