快速求排列组合C(m,n)%mod

写在前面:
1. 为防止产生n和m的歧义,本博文一律默认n >= m
2. 本博文默认mod = 10^6+3
3. 本博文假设读者已知排列组合公式

C(m,n)=n!(n−m)!∗m!

4. 普通的小数据就不用多说了,直接用公式,当然别忘了取模

C(m,n)=C(m−1,n−1)+C(m,n−1)

现在我们讨论当n可达10^9数量级大小时的算法。

步骤一:我们先把分子阶乘写成以下形式

n!=X∗modY

步骤二:对分母元素乘机求逆元。此时我们假设得到了以下方程式:

n!(n−m)!∗m!=A∗modBGamma(T)∗modD=A∗C∗modBmodD

其中Gamma(T)表示分母剩余数字的乘积,C为他的逆元。

步骤三:显然根据上式我们就可以得出结论了

  • 如果B > D ,那么我们的最终答案为 C(m,n)% mod = 0
  • 否则我们的答案为C(m,n) = (A * C) % mod

注意事项

  • 求A的过程中,我们会发现最后的结果会变成:

    [1∗2∗...∗(mod−1)∗(mod+1)∗…]∗modB∗[1∗2∗…∗(n/mod)]
  • 如果有多组数据,而mod的大小又不变,那么我们完全可以对k!%mod进行预处理

  • 在对分母的每个元素求逆元时,我们可以由mod是素数直接用欧拉函数求出其逆元

    1. 欧拉函数

      phi(mod)=mod−1
    2. 求逆元,用快速幂,同时别忘了取模
      inv(x)=xphi(mod)−1

最后代码如下:

@Frosero
#include <iostream>
#include <algorithm>
using namespace std; const long long mod = 1000003;
long long mul[1000100]; long long pow_mod(long long a ,long long p){ //递归快速幂
if(p == 0) return 1;
long long ans = pow_mod(a,p/2);
ans = ans * ans % mod;
if(p % 2) ans = ans * a % mod;
return ans;
} void ask(long long n,long long &x,long long y){ //将阶乘 n! 拆分成 x * mod ^ y 的形式
y = n / mod;
x = (pow_mod(mul[mod - 1],y) * mul[n - y * mod] * mul[y]) % mod;
} int main(){
mul[0] = mul[1] = 1;
for(long long i = 2 ;i < mod ;i++){ //预处理 0 至 mod-1 的阶乘取模值
mul[i] = mul[i - 1] * i % mod;
} long long m,n,x,y;
long long A,B,C,D;
while(cin >> m >> n){ //对应上文中所讲的 即转换成 A * C * mod ^ B / mod ^ D 的形式
ask(n,A,B); ask(m,C,D); ask(n-m,x,y);
D += y;
C = pow_mod(C,mod - 2) * pow_mod(x,mod - 2) % mod;
if(B > D) cout<<0<<endl;
else cout<<A * C % mod<<endl;
}
return 0;
}

补充

  1. 由以上可知算法时间复杂度和mod的取值大小有关
  2. 如果n的大小超过mod * mod 时要考虑特殊情况,读者可以自己想
  3. 如果mod不是素数时,我们可以换一种方法。希望大家自己思考,这里就不啰嗦了

快速求排列C(m,n)加取模的更多相关文章

  1. 快速求排列组合 lucas定理

    对于C(n, m) mod p.这里的n,m,p(p为素数)都很大的情况. 就不能再用C(n, m) = C(n - 1,m) + C(n - 1, m - 1)的公式递推了. 一般lucas定理的p ...

  2. 牛客Wannafly挑战赛13-BJxc军训-费马小定理、分式取模、快速幂

    参考:https://blog.csdn.net/qq_40513946/article/details/79839320 传送门:https://www.nowcoder.com/acm/conte ...

  3. [hdu5392 Infoplane in Tina Town]置换的最小循环长度,最小公倍数取模,输入挂

    题意:给一个置换,求最小循环长度对p取模的结果 思路:一个置换可以写成若干循环的乘积,最小循环长度为每个循环长度的最小公倍数.求最小公倍数对p取模的结果可以对每个数因式分解,将最小公倍数表示成质数幂的 ...

  4. 牛客小白月赛9 A签到(分数取模,逆元)

    传送门 对分母求一下逆元,把除法取模变成乘法取模,逆元介绍看这里 这种方法只适合模为质数的情况 #include<bits/stdc++.h> using namespace std; ; ...

  5. np问题(大数阶乘取模)

    转自 np问题 题目描述: LYK 喜欢研究一些比较困难的问题,比如 np 问题. 这次它又遇到一个棘手的 np 问题.问题是这个样子的:有两个数 n 和 p,求 n 的阶乘对 p 取模后的结果. L ...

  6. The 2018 ACM-ICPC China JiangSu Provincial Programming Contest快速幂取模及求逆元

    题目来源 The 2018 ACM-ICPC China JiangSu Provincial Programming Contest 35.4% 1000ms 65536K Persona5 Per ...

  7. 九度OJ 1085 求root(N, k) -- 二分求幂及快速幂取模

    题目地址:http://ac.jobdu.com/problem.php?pid=1085 题目描述: N<k时,root(N,k) = N,否则,root(N,k) = root(N',k). ...

  8. NYOJ--102--次方求模(快速求幂取模)

    次方求模 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 求a的b次方对c取余的值   输入 第一行输入一个整数n表示测试数据的组数(n<100)每组测试只有一 ...

  9. 二分求幂/快速幂取模运算——root(N,k)

    二分求幂 int getMi(int a,int b) { ; ) { //当二进制位k位为1时,需要累乘a的2^k次方,然后用ans保存 == ) { ans *= a; } a *= a; b / ...

随机推荐

  1. 【leetcode】945. Minimum Increment to Make Array Unique

    题目如下: Given an array of integers A, a move consists of choosing any A[i], and incrementing it by 1. ...

  2. python用户名密码限定次数登录

    """ 1. 用户输入帐号密码进行登陆 2. 用户信息保存在文件内 3. 用户密码输入错误三次后锁定用户"""" test.txt ...

  3. springCloud配置(microServiceProvider)

    server: port: 8001 mybatis: config-location: classpath:mybatis/mybatis.cfg.xml # mybatis配置文件所在路径 typ ...

  4. comet4j js中写法

    <script type="text/javascript" src="${ctxStatic}/common/js/comet4j.js">< ...

  5. Linq 使用Startswith 出现空引用的问题

    一.问题 我使用的是Entity Fromwork CodeFirst来操作数据库,昨天在使用startswith查询数据的时候发现一个问题,就是经常一直报空引用的错误,查了很久才找到原因,这里做一个 ...

  6. linux基础知识-常用命令

    ifconfig :查看当前ip hostname:查看主机名 vim /etc/hosts:修改地址映射 service iptables status : 查看防火墙状态 chkconfig ip ...

  7. SCP-bzoj-1019

    项目编号:bzoj-1019 项目等级:Safe 项目描述: 戳这里 特殊收容措施: 对于一个hanoi,知道了各种移动操作的优先级,也就确定了方案.可以证明对于盘子数为N的hanoi,任意移动方案都 ...

  8. [NOIP模拟测试30]题解

    A.Return 出题人大概是怕自己的中文十级没人知道,所以写了这么一个***题面.可能又觉得这题太水怕全场A掉后自己面子过不去,于是又故意把输出格式说的含糊不清.(鬼知道"那么输出-1&q ...

  9. tomcat 高并发

    转自 http://blog.csdn.net/feng27156/article/details/19420695 一.容器简化了程序员自身的多线程编程. 各种Web容器,如Tomcat,Resio ...

  10. Ruby 技能图谱

    # Ruby 技能图谱 说明: 本图谱只捡重点的列举,并非包含全部.文中所列举或没有列举的资源信息都可以在[awesome-ruby](https://github.com/markets/aweso ...