快速求排列C(m,n)加取模
快速求排列组合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是素数直接用欧拉函数求出其逆元
- 欧拉函数
phi(mod)=mod−1
- 求逆元,用快速幂,同时别忘了取模
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;
}
补充
- 由以上可知算法时间复杂度和mod的取值大小有关
- 如果n的大小超过mod * mod 时要考虑特殊情况,读者可以自己想
- 如果mod不是素数时,我们可以换一种方法。希望大家自己思考,这里就不啰嗦了
快速求排列C(m,n)加取模的更多相关文章
- 快速求排列组合 lucas定理
对于C(n, m) mod p.这里的n,m,p(p为素数)都很大的情况. 就不能再用C(n, m) = C(n - 1,m) + C(n - 1, m - 1)的公式递推了. 一般lucas定理的p ...
- 牛客Wannafly挑战赛13-BJxc军训-费马小定理、分式取模、快速幂
参考:https://blog.csdn.net/qq_40513946/article/details/79839320 传送门:https://www.nowcoder.com/acm/conte ...
- [hdu5392 Infoplane in Tina Town]置换的最小循环长度,最小公倍数取模,输入挂
题意:给一个置换,求最小循环长度对p取模的结果 思路:一个置换可以写成若干循环的乘积,最小循环长度为每个循环长度的最小公倍数.求最小公倍数对p取模的结果可以对每个数因式分解,将最小公倍数表示成质数幂的 ...
- 牛客小白月赛9 A签到(分数取模,逆元)
传送门 对分母求一下逆元,把除法取模变成乘法取模,逆元介绍看这里 这种方法只适合模为质数的情况 #include<bits/stdc++.h> using namespace std; ; ...
- np问题(大数阶乘取模)
转自 np问题 题目描述: LYK 喜欢研究一些比较困难的问题,比如 np 问题. 这次它又遇到一个棘手的 np 问题.问题是这个样子的:有两个数 n 和 p,求 n 的阶乘对 p 取模后的结果. L ...
- The 2018 ACM-ICPC China JiangSu Provincial Programming Contest快速幂取模及求逆元
题目来源 The 2018 ACM-ICPC China JiangSu Provincial Programming Contest 35.4% 1000ms 65536K Persona5 Per ...
- 九度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). ...
- NYOJ--102--次方求模(快速求幂取模)
次方求模 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 求a的b次方对c取余的值 输入 第一行输入一个整数n表示测试数据的组数(n<100)每组测试只有一 ...
- 二分求幂/快速幂取模运算——root(N,k)
二分求幂 int getMi(int a,int b) { ; ) { //当二进制位k位为1时,需要累乘a的2^k次方,然后用ans保存 == ) { ans *= a; } a *= a; b / ...
随机推荐
- Android Studio 打包生成正式apk(XXX-release.apk)的两种方式
{ 方式一:使用Android Studio生成1.点击Build->Generate Signed apk,首次点击可能会提示输入操作系统密码2.弹出如下对话框,还没有生成过keystore ...
- 洛谷P1122 最大子树和 (树状dp)
题目描述 小明对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题.一天他早晨骑车去上课,路上见到一个老伯正在修剪花花草草,顿时想到了一个有关修剪花卉的问题.于是当日课后,小明 ...
- 初学Linux基本的命令操作应当记牢
Linux管理文件和目录的命令 命令 功能 命令 功能 pwd 显示当前目录 ls 查看目录下的内容 cd 改变所在目录 cat 显示文件的内容 grep 在文件中查找某字符 cp 复制文件 touc ...
- React的contextType的使用方法简介
上一篇介绍了Context的使用方法.但是Context会让组件变得不纯粹,因为依赖了全局变量.所以这决定了Context一般不会大规模的使用.所以一般在一个组件中使用一个Context就好. 由于C ...
- 新手指南:DVWA-1.9全级别教程之SQL Injection
*本文原创作者:lonehand,转载须注明来自FreeBuf.COM 目前,最新的DVWA已经更新到1.9版本(http://www.dvwa.co.uk/),而网上的教程大多停留在旧版本,且没有针 ...
- vue-cesium中经纬度写反了,报错
vue-cesium中经纬度写反了,报错 [Vue warn]: Invalid prop: custom validator check failed for prop "position ...
- camunda流程实例启动的一些简单操作
public class ZccRuntimeService { RuntimeService runtimeService; RepositoryService repositoryService; ...
- camunda用户的一些简单操作
act_id_group:存放组信息act_id_membership:存放用户与组的相关信息act_id_user:存放用户act_id_info:存放用户个人信息act_id_tenant:存放租 ...
- Module not found: Error: Can't resolve '@babel/runtime/helpers/classCallCheck' and Module not found: Error: Can't resolve '@babel/runtime/helpers/defineProperty'
These two mistakes are really just one mistake, This is because the following file @babel/runtime ca ...
- python-模块 time, os, sys
时间模块 和时间有关系的我们就要用到时间模块.在使用模块之前,应该首先导入这个模块. #常用方法 1.time.sleep(secs) (线程)推迟指定的时间运行.单位为秒. 2.time.time( ...