算法笔记--排列组合
2017-06-30 19:52
274 查看
小数据时:C(a,b)
先乘后除不会出现截断以及尽大可能不超数据范围。LL最大C(33,66);
递推写法(可以取膜)
数据比较大时用Lucas定理:Lucas(a,b)=C(a,b)%p
C(n, m) mod p = n!/(m!(n - m)!) mod p。显然除法取模,这里要用到m!(n-m)!的逆元。
根据费马小定理:
已知(a, p) = 1,则 a^(p-1) ≡ 1 (mod p), 所以 a*a^(p-2) ≡ 1 (mod p)。
也就是 (m!(n-m)!)的逆元为 (m!(n-m)!)^(p-2) ;
写法二
先乘后除不会出现截断以及尽大可能不超数据范围。LL最大C(33,66);
int ans=1; for(int i=0;i<=b;i++){ ans*=(a-i); ans/=(i+1); }
递推写法(可以取膜)
long long c[1005][1005]; void init() { c[1][1]=1; for(int i=0;i<=1000;i++) c[i][0]=c[i][i]=1; for(int i=2;i<=1000;i++) { for(int j=1;j<=i;j++) { c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod; } } }
数据比较大时用Lucas定理:Lucas(a,b)=C(a,b)%p
C(n, m) mod p = n!/(m!(n - m)!) mod p。显然除法取模,这里要用到m!(n-m)!的逆元。
根据费马小定理:
已知(a, p) = 1,则 a^(p-1) ≡ 1 (mod p), 所以 a*a^(p-2) ≡ 1 (mod p)。
也就是 (m!(n-m)!)的逆元为 (m!(n-m)!)^(p-2) ;
#include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #define LL long long using namespace std; LL n,m,p; LL quick_mod(LL a, LL b) { LL ans = 1; a %= p; while(b) { if(b & 1) { ans = ans * a % p; b--; } b >>= 1; a = a * a % p; } return ans; } LL C(LL n, LL m) { if(m > n) return 0; LL ans = 1; for(int i=1; i<=m; i++) { LL a = (n + i - m) % p; LL b = i % p; ans = ans * (a * quick_mod(b, p-2) % p) % p; } return ans; } LL Lucas(LL n, LL m) { if(m == 0) return 1; return C(n % p, m % p) * Lucas(n / p, m / p) % p; }
写法二
//求C(n,m)%p p(素数)最大为10^5。a,b可以很大! #define LL long long LL PowMod(LL a, LL b, LL MOD){ LL ret = 1; while (b) { if (b&1) ret = (ret*a)%MOD; a = (a*a) % MOD; b >>= 1; } return ret; } LL fac[100005]; LL Get_Fact(LL p) { fac[0] = 1; for (int i = 1;i <= p; i++) fac[i] = (fac[i-1]*i)%p; } LL Lucas(LL n, LL m, LL p) { LL ret = 1; while (n && m) { LL a = n%p, b = m%p; if (a < b) return 0; ret = (ret*fac[a]*PowMod(fac[b]*fac[a-b]%p, p-2, p))%p; n /= p; m /= p; } return ret; } int main() { LL n, m, p; scanf("%I64d %I64d %I64d", &n, &m, &p); Get_Fact(p); printf("%I64d\n", Lucas(n, m, p)); return 0; }
相关文章推荐
- 排列组合与回溯算法浅谈
- 排列、组合及算法
- 一个排列、组合的生成算法 [zz]
- 一个排列组合算法---裂变算法
- 一个排列组合算法---裂变算法
- 高效率的排列组合算法(java实现)
- 排列组合问题的通用算法
- 排列组合的一些算法
- 求N选M的组合和求全排列的巧妙算法
- 一个排列组合算法---裂变算法
- 排列组合与回溯算法
- 排列组合算法1:生成全部有序列b
- 排列组合算法1:生成全部有序列
- 求N选M的组合和求全排列的巧妙算法 - 算法艺术 - Hello, busycai!
- 排列组合问题的通用算法
- 类似stl中排列算法的组合算法
- 高效率的排列组合算法
- 有人机交互能力的排列组合算法(C++版)
- VB.NET 排列组合算法实现
- 排列组合-打印出一个数组的元素的所有排列方式-算法