快速求排列组合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】931. Minimum Falling Path Sum

    题目如下: Given a square array of integers A, we want the minimum sum of a falling path through A. A fal ...

  2. 2019牛客多校第五场 B - generator 1 矩阵快速幂+十倍增+二进制倍增优化

    B - generator 1 题意 给你\(x_{0}.x_{1}.a.b.b.mod\),根据\(x_{i} = a*x_{i-1} + b*x_{i-2}\)求出\(x_{n}\) 思路 一般看 ...

  3. 关于Burp Suite不能抓包的解决方法

    一.Burp Suite有时能抓到包,有时不能抓到包 解决方法: 出现这种问题的原因就是代理没有设置成全局的,只是设置成了局部的. 打开IE浏览器,依次打开工具->Internet 属性-> ...

  4. C# 语法特性

    C# 2.0 1.泛型(Generics). 2.泛型方法.泛型委托.泛型接口. 3.泛型约束(constraints). 4.部分类(partial). 5.匿名方法. C#3.0/C#3.5 1. ...

  5. ListView 分页显示(转载+修改)下

    通过实践发现,尚大大在判断”上一页“按钮和”下一页按钮“是否可用的地方,有问题: 原代码: public void checkButton(){ //索引值小于等于0,表示不能向前翻页了,以经到了第一 ...

  6. JS-监听整个页面上的DOM树变化

    # [在线预览](https://jsfiddle.net/1010543618/fyf913t0/) ## 方法 - 使用<Web API 接口>的<MutationObserve ...

  7. shell awk匹配字符串(从配置文件)

    配置文件 config.properties xxx_yyy_lib_path="路径" xxx_yyy_bin_path="路径" 想通过shell来读入路径 ...

  8. 论一个PHP项目上线的注意点

    一.后端问题 服务器配置要跟上流量 预估QPS时要给足未知流量的空间 后端数据库设计要根据项目大小来相对应,小型流量单表就可以,但是中大型要分库分表 在处理执行修改的操作时一定要多一层判断(判断是否已 ...

  9. 使用mybatis进行一对多嵌套查询时出错:输出结果:Country{id=2, name='美国', minister=[null]}

    即Minister类作为Country类的关联属性. 查询的输出结果是:Country{id=2, name='美国', minister=[null]} <!--mapper.xml内容--& ...

  10. Tomcat启动脚本(1)startup.bat

    @echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor lic ...