之前看了乘法逆元(详见除法取模与逆元),发现不能处理不互质的情况,于是去找方法,最后找到了Lucas定理。。。
虽然与期待中的不一样,但是还是非常有用的。

(1)Lucas定理:

若p为素数,则有:

Cnm≡∏i=0kCnimi(modp)

C_m^n \equiv \prod_{i=0}^kC_{m_i}^{n_i} \pmod p

n=nkpk+nk−1pk−1+...+n0

n = n_kp^k+n_{k-1}p^{k-1}+...+n_0

m=mkpk+mk−1pk−1+...+m0

m = m_kp^k+m_{k-1}p^{k-1}+...+m_0
ni,mi n_i,m_i即为把n,m转换成p进制后对应的第i+1位数字。
因为a的p进制的最后一位为a%p,所以原公式可以转化为:

Cmn≡C[mp][np]×Cmmodpnmodp(modp)

C_n^m \equiv C_{[\frac np]}^{[\frac mp]} \times C_{n\mod p}^{m\mod p} \pmod p
这个就是我们常使用的公式。
证明:
我们可以用归纳法证明整个定理。我们有下面的式子成立:

(1+x)n≡(1+x)p[np](1+x)nmodp≡(1+xp)[np](1+x)nmodp≡{∑i=0[np]Ci[np]xpi}{∑j=0nmodpCjnmodpxj}(modp)

(1+x)^n \equiv (1+x)^{p[\frac n p]}(1+x)^{n\mod p}\equiv (1+x^p)^{[\frac n p]}(1+x)^{n\mod p}\equiv \{\sum_{i = 0}^{[\frac np]}C_{[\frac np]}^ix^{pi}\}\{\sum_{j=0}^{n\mod p}C_{n\mod p}^jx^j\} \pmod p

上式左右两边的x的某项 xm(m≤n) x^m(m\le n)的系数对模p同余。
其中左边的 xm x^m的系数是 Cmn C_n^m。 而由于 nmodp n\mod p和 mmodp m\mod p都小于 p p,因此右边的xmx^m一定是由 x[mp]p x^{[\frac mp]p} 和 xmmodp x^{m\mod p} (即 i=[mp],j=mmodp i=[\frac mp] , j=m\mod p ) 相乘而得,因此有: Cmn=C[mp][np]×Cmmodpnmodp(modp) C_n^m=C_{[\frac np]}^{[\frac mp]} \times C_{n\mod p}^{m\mod p} \pmod p。

(2)扩展Lucas:

若p不是素数,我们将p分解质因数,将 Cmn C_n^m分别按照(1)中的方法求对p的质因数的模,然后用中国剩余定理合并。
例如:
当我们需要计算 Cmnmodp C_n^m\mod p,其中 p=pq11×pq22×...×pqkk p = p_1^{q_1}\times p_2^{q_2}\times ...\times p_k^{q_k},我们可以求出:

Cmn≡ai(modpqii)(1<i<k)

C_n^m\equiv a_i\pmod {p_i^{q_i}} (1\lt i \lt k)
然后对于方程组:

x≡ai(modpqii)(1<i<k)

x\equiv a_i \pmod {p_i^{q_i}}(1\lt i\lt k)
我们可以求出满足条件的最小的 x x,记为x0x_0。
那么我们有:

Cmn≡x0(modp)

C_n^m\equiv x_0\pmod p
但是,我们发现, pqii p_i^{q_i}并不是一个素数,它是某个素数的某次方。
下面我们介绍如何计算 Cmnmodpt(t≥2,p为素数) C_n^m \mod p^t(t\ge2,p为素数)。
计算 Cmnmodpt C_n^m\mod p^t:
我们知道, Cmn=n!m!(n−m)! C_n^m=\frac {n!}{m!(n-m)!},若我们可以计算出 n!modpt n!\mod p^t,我们就能计算出 m!modpt m!\mod p^t以及 (n−m)!modpt (n-m)!\mod p^t。我们不妨设 x=n!modpt,y=m!modpt,z=(n−m)!modpt, x=n!\mod p^t,y=m!\mod p^t,z=(n-m)!\mod p^t,那么答案就是 x×reverse(y,pt)×reverse(z,pt) x\times reverse(y,p^t)\times reverse(z,p^t)( reverse(a,b) reverse(a,b)表示计算a对b的乘法逆元)。那么下面问题就转化成如何计算 n!modpt n!\mod p^t。例如 p=3,t=2,n=19 p=3,t=2,n=19

n!=1×2×3×4×5×6×7×8×...×19=(1×2×4×5×7×8×...×16×17×19)×(3×6×9×12×15×18)=(1×2×4×5×7×8×...×16×17×19)×36×(1×2×3×4×5×6)

n!=1\times2\times3\times4\times5\times6\times7\times8\times ...\times19=(1\times2\times4\times5\times7\times8\times...\times16\times17\times19)\times(3\times6\times9\times12\times15\times18)=(1\times2\times4\times5\times7\times8\times...\times16\times17\times19)\times3^6\times(1\times2\times3\times4\times5\times6)

后面的部分恰好是 (n/p)! (n/p)!,于是递归即可。前半部分是以 pt p^t为周期的 (1×2×4×5×7×8)≡(10×11×13×14×16×17)(mod9) (1\times2\times4\times5\times7\times8)\equiv(10\times11\times13\times14\times16\times17)\pmod9。下面是孤立的19,可以知道孤立出来的长度不超过 pt p^t,于是直接计算即可。对于最后剩下的 36 3^6这些数我们只要计算出 n!,m!,(n−m)! n!,m!,(n-m)!里含有多少个 p p(不妨设x,y,zx,y,z),那么 x−y−z x-y-z就是 Cmn C_n^m中 p p的个数,直接计算就行。

下面是计算CmnmodpC_n^m\mod p的代码:

#include<cstdio>
#include<algorithm>
using namespace std;long long pow(long long a, long long b, long long p) {long long res = 1;while(b) {if(b&1) res = res*a%p;a = a*a%p;b >>= 1;}return res;
}long long exgcd(long long a, long long b, long long& x, long long& y) {if(!b) {x = 1;y = 0;return a;}long long res = exgcd(b, a%b, y, x);y -= (a/b)*x;return res;
}long long reverse(long long a, long long p) {long long x, y;exgcd(a, p, x, y);return (x % p + p)%p;
}long long C(long long n, long long m, long long p) {if(m>n) return 0;long long res = 1, i, a, b;for(i = 1; i <= m; i++) {a = (n+1-i) % p;b = reverse(i%p, p);res = res*a%p*b%p;}return res;
}long long Lucas(long long n, long long m, long long p) {if(m == 0) return 1;return Lucas(n/p, m/p, p)*C(n%p, m%p, p) % p;
}long long cal(long long n, long long a, long long b, long long p) {if(!n) return 1;long long i, y = n/p, tmp = 1;for(i = 1; i <= p; i++) if(i%a) tmp = tmp*i%p;long long ans = pow(tmp, y, p);for(i = y*p+1; i <= n; i++) if(i%a) ans = ans*i%p;return ans * cal(n/a, a, b, p)%p;
}long long multiLucas(long long n, long long m, long long a, long long b, long long p) {long long i, t1, t2, t3, s = 0, tmp;for(i = n; i; i/=a) s += i/a;for(i = m; i; i/=a) s -= i/a;for(i = n-m; i; i/=a) s -= i/a;tmp = pow(a, s, p);t1 = cal(n, a, b, p);t2 = cal(m, a, b, p);t3 = cal(n-m, a, b, p);return tmp*t1%p*reverse(t2, p)%p*reverse(t3, p)%p;
}long long exLucas(long long n, long long m, long long p) {long long i, d, c, t, x, y, q[100], a[100], e = 0;for(i = 2; i*i <= p; i++) {if(p % i == 0) {q[++e] = 1;t = 0;while(p%i==0) {p /= i;q[e] *= i;t++;}if(q[e] == i) a[e] = Lucas(n, m, q[e]);else a[e] = multiLucas(n, m, i, t, q[e]);}}if(p > 1) {q[++e] = p;a[e] = Lucas(n, m, p);}for(i = 2; i <= e; i++) {d = exgcd(q[1], q[i], x, y);c = a[i]-a[1];if(c%d) exit(-1);t = q[i]/d;x = (c/d*x%t+t)%t;a[1] = q[1]*x+a[1];q[1] = q[1]*q[i]/d;}return a[1];
}int main() {long long n, m, p;scanf("%lld%lld%lld", &n, &m, &p);printf("%lld\n", exLucas(n, m, p));return 0;
}

Lucas定理与扩展Lucas相关推荐

  1. 专题·Lucas定理【including Lucas定理,扩展Lucas

    初见安~这里是数论专题(6)[详见数论专栏 本篇有前置知识点需要掌握,建议先了解下:费马小定理,中国剩余定理,乘法逆元 一.Lucas定理 Lucas定理用于求解的组合数取模的问题.其中p为质数. 组 ...

  2. lucas定理及扩展lucas定理

    还有一篇关于lucas定理的比较好的文章:关于LUCAS二项式系数同余定理的一些推广 转载原文链接:http://www.cnblogs.com/jianglangcaijin/p/3446839.h ...

  3. lucas定理、拓展lucas定理学习小结

    lucas定理 正题 首先,这玩意就是下面这个式子: C m n % p = C m / p n / p ∗ C m % p n % p % p C_m^n\%p=C_{m/p}^{n/p}*C_{m ...

  4. 『Lucas定理以及拓展Lucas』

    Lucas定理 在『组合数学基础』中,我们已经提出了\(Lucas\)定理,并给出了\(Lucas\)定理的证明,本文仅将简单回顾,并给出代码. \(Lucas\)定理:当\(p\)为质数时,\(C_ ...

  5. Lucas定理和拓展Lucas定理

    用途 对于一个组合数求值的问题,一般运用阶乘来求,但有时候阶乘太大,就会超时. 而 L u c a s Lucas Lucas 定理和拓展 L u c a s Lucas Lucas 定理就是用来解决 ...

  6. 【luogu P3807】【模板】卢卡斯定理/Lucas 定理(含 Lucas 定理证明)

    [模板]卢卡斯定理/Lucas 定理 题目链接:luogu P3807 题目大意 求 C(n,n+m)%p 的值. p 保证是质数. 思路 Lucas 定理内容 对于非负整数 nnn,mmm,质数 p ...

  7. Lucas定理:线性求所有逆元的方法

    Miskcoo's Space,版权所有丨如未注明,均为原创 转载请注明转自:http://blog.miskcoo.com/2014/09/linear-find-all-invert 主要绕过费马 ...

  8. lucas定理 学习笔记

    lucas定理 学习笔记 文章目录 lucas定理 学习笔记 介绍 combination 题目描述 输入格式 输出格式 样例 输入样例1 输出样例2 分析 code 扩展lucas 介绍 lucas ...

  9. HDU 5226 Tom and matrix(组合数学+Lucas定理)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5226 题意:给一个矩阵a,a[i][j] = C(i,j)(i>=j) or 0(i < ...

最新文章

  1. 深度学习(十三)caffe之训练数据格式
  2. 操作系统设计与实现第3版笔记与minix3心得(5)-操作系统发展历史(3)
  3. 牛客网_PAT乙级_1020完美数列(25)【vector sort 最后一个测试用例超时】
  4. 重庆计算机硬件市场主要分布地,重庆市草地资源分布现状及类型特征
  5. 多线程编程-工具篇-BlockingQueue
  6. IT职场人生系列之三:第一份工作
  7. 详细解读Spark的数据分析引擎:Spark SQL
  8. 调研报告|在线语音识别改进之 RNN-T 训练
  9. 安徽省学考计算机操作,安徽省教育考试院全国计算机等级考试网上报名流程与操作步骤...
  10. PADS——导出Gerber文件
  11. 机器学习导论——关于数据集的概念
  12. 台式计算机cpu允许温度,台式机cpu温度多少正常 台式机cpu正常温度
  13. 台式计算机usb口不识别鼠标,如何解决插入鼠标提示无法识别USB设备的问题
  14. 基于因果逻辑库的定性事件结果及结果方向性预测
  15. Inventor记录
  16. 大连暗泉渗透/红队岗面试题(高级渗透测试工程师面试题)总结
  17. Vue中props属性
  18. python的常见矩阵除法_Python矩阵除法
  19. IOS 使用支付宝的注意事项
  20. java版本qq登陆界面_java实现QQ登陆界面

热门文章

  1. 亚马逊云科技——如何在中国市场破局?
  2. linux少了 dev dm设备,已解决: Linux中安装了powerpath之后为什么还会有dm设备? - Dell Community...
  3. 聚美优品CEO陈欧:“陈欧体”传奇式逆袭
  4. 白羊座爱情的预测,以及主要的日食,占星术预测2011年的影响
  5. 【调剂】关于安徽工程大学2022年硕士研究生招生相关问题答考生问
  6. 关于SN74HC14PW
  7. 聚类dbi指数_聚类算法
  8. Mysql的下载安装以及配置(超详细)
  9. Oracle如何用单字段或多字段进行查重
  10. 决策树算法实现:泰坦尼克号乘客生存预测 (python实现)