一、 一般组合数计算
若对 a n s ans ans取模,则无法保证下一步是否能被整除,所以只能对最后的结果取模
时间复杂度:
O
(
m
)
O(m)
O(m)
m
o
d
mod
mod的要求:无
有效范围:
1
<
=
n
,
m
<
=
60
1<=n,m<=60
1<=n,m<=60
//一般方法求C(n,m)最后取模。C(62,28)溢出。有效范围1<n,m<=60
ll C(int n, int m) {
if(n<0 || m<0 || n<m) return 0;
ll ans = 1;
for (int i=1; i<=m; i++) {
ans *= (n - m + i);
ans /= i;
}
return ans % mod;
}
二、 杨辉三角
可以在过程中取模,但时间复杂度较高
公式:
C
(
n
,
m
)
=
C
(
n
−
1
,
m
)
+
C
(
n
−
1
,
m
−
1
)
C(n,m)=C(n-1,m)+C(n-1,m-1)
C(n,m)=C(n−1,m)+C(n−1,m−1)
时间复杂度:
O
(
n
m
)
O(nm)
O(nm)
m
o
d
mod
mod的要求:无
有效范围:
1
<
=
n
,
m
<
=
1000
1<=n,m<=1000
1<=n,m<=1000
//杨辉三角求C(n,m)
ll matrix[110][110];
ll C(int n, int m) {
if(n<0 || m<0 || n<m) return 0;
ll ans = 0;
matrix[1][0] = matrix[1][1] = 1;
for (int i=2; i<=n; i++) {
int k = min(i, m);
for(int j=0; j<=k; j++) {
if (j==0 || j==i) matrix[i][j] = 1;
else matrix[i][j] = (matrix[i-1][j] + matrix[i-1][j-1]) % mod;
}
}
return matrix[n][m];
}
三、 逆元
公式:
C
(
n
,
m
)
=
n
!
m
!
×
(
n
−
m
)
!
C(n,m)=\cfrac{n!}{m!×(n-m)!}
C(n,m)=m!×(n−m)!n!
时间复杂度:
O
(
l
o
g
p
+
n
)
O(logp+n)
O(logp+n)
m
o
d
mod
mod要求:
p
p
p为质数,且
m
<
p
m<p
m<p 或
G
C
D
(
p
,
m
)
=
1
GCD(p, m)=1
GCD(p,m)=1
有效范围:
1
<
=
n
,
m
<
=
1
0
6
1<=n,m<=10^6
1<=n,m<=106
ll fac[1<<21];
ll qpow(ll a, ll b, ll c) {
ll ret = 1;
a = a % c;
while (b) {
if (b & 1) ret = ret * a % c;
a = a * a % c;
b >>= 1;
}
return ret;
}
void init() { //先打出阶乘,节省时间
fac[1] = fac[0] = 1;
for (int i=2; i<=(1<<20); i++) {
fac[i] = fac[i - 1] * i % mod;
}
}
ll C(ll n, ll m) { //逆元求组合数
return fac[n] * qpow(fac[m] * fac[n - m] % mod, mod - 2, mod) % mod;
}
线性预处理逆元:
const int maxf = 1e7 + 5;
ll fac[maxf], inv[maxf], invf[maxf];
void init(){
fac[0] = inv[0] = invf[0] = 1;
fac[1] = inv[1] = invf[1] = 1;
for(int i=2; i<maxf; i++){
fac[i] = fac[i-1] * i % mod;
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
invf[i] = inv[i] * invf[i-1] % mod; // 可用 fac[maxf] 反向求出
}
}
ll C(ll n, ll m){
if(n<0 || m<0 || n<m) return 0;
return fac[n] * invf[m] % mod * invf[n-m] % mod;
}
四、 分解因子
时间复杂度:
O
(
n
)
O(n)
O(n)
m
o
d
mod
mod的要求:无(可为合数)
有效范围:
1
<
=
n
,
m
,
p
<
=
1
0
6
1<=n,m,p<=10^6
1<=n,m,p<=106
const int maxp = 1e6 + 5;
int pnum = 0, ispri[maxp], pri[maxp];
inline void pri_table() {
for(int i=2; i<maxp; i++) ispri[i] = 1;
for(int i=2; i<maxp; i++) {
if(ispri[i]) pri[pnum++] = i; // 注意略有修改
for(int j=0; i*pri[j]<maxp && j<pnum; j++) {
ispri[i*pri[j]] = 0;
if(i%pri[j]==0) break;
}
}
}
ll qpow(ll a, ll b, ll c) {
ll ans = 1;
a = a % c;
while (b) {
if(b & 1) ans = (ans * a) % c;
b >>= 1;
a = (a * a) % c;
}
return ans;
}
//获得n!中因子p的个数
ll getPNum(ll n, ll p) {
ll ans = 0;
while (n) {
ans += n / p;
n /= p;
}
return ans;
}
//利用因子求C(n,m)
ll CFactor(ll n, ll m) {
if (m > n) return 0;
ll ans = 1;
for (int i=0; pri[i]!=0 && pri[i]<=n; i++) {
ll a = getPNum(n, pri[i]);
ll b = getPNum(m, pri[i]);
ll c = getPNum(n - m, pri[i]);
a -= (b + c);
ans *= qpow(pri[i], a, mod);
ans %= mod;
}
return ans;
}
五、 Lucas定理*
m
o
d
mod
mod的要求:质数
有效范围:
1
<
=
n
,
m
,
p
<
=
1
0
9
1<=n,m,p<=10^9
1<=n,m,p<=109
① p p p较大、不进行预处理
ll qpow(ll a, ll b, ll c) {
ll ans = 1;
a %= c;
while(b) {
if(b & 1) ans = ans * a % c;
b >>= 1;
a = a * a % c;
}
return ans;
}
//x关于p的逆元,p为素数
ll inv(ll x, ll p) {
return qpow(x, p - 2, p);
}
//组合数C(n, m) % p
ll C(ll n, ll m, ll p) {
if(m > n) return 0;
ll up = 1, down = 1;//分子分母;
for(int i = n-m+1; i <= n; i++) up = up * i % p;
for(int i = 1; i <= m; i++) down = down * i % p;
return up * inv(down, p) % p;
}
ll Lucas(ll n, ll m) {
if(m == 0) return 1;
return C(n % mod, m % mod, mod) * Lucas(n / mod, m / mod) % mod;
}
② p p p较小、 p < 1 0 6 p<10^6 p<106、半预处理
ll fac[1<<20];
ll qpow(ll a, ll b, ll c) { //快速幂
ll ans = 1;
a = a % c;
while (b) {
if (b & 1) ans = ans * a % c;
b >>= 1;
a = a * a % c;
}
return ans;
}
void init() { //先打出阶乘,节省时间
fac[1] = 1;
for (int i=2; i<=(1<<20); i++) {
fac[i] = fac[i - 1] * i % mod;
}
}
ll C(ll n, ll m) { //逆元求组合数
return fac[n] * qpow(fac[m] * fac[n - m] % mod, mod - 2, mod) % mod;
}
ll Lucas(ll n, ll m) {
if(m == 0) return 1;
return C(n % mod, m % mod) * Lucas(n / mod, m / mod) % mod;
}
六、 拓展Lucas定理*
m
o
d
mod
mod的要求:无
有效范围:
1
<
=
n
,
m
,
p
<
=
1
0
9
1<=n,m,p<=10^9
1<=n,m,p<=109
即
n
,
m
n,m
n,m都很大且
p
p
p不为质数的时候,用此定理
ll pow(ll a, ll b, ll p) {
ll ans = 1;
a %= p;
while(b) {
if(b & 1) ans = ans * a % p;
b >>= 1;
a = a * a % p;
}
return ans;
}
// 求解ax+by=gcd(a, b),返回值为gcd(a, b)
ll extgcd(ll a, ll b, ll &x, ll &y) {
ll d = a;
if(b) {
d = extgcd(b, a % b, y, x);
y -= (a / b) * x;
} else x = 1, y = 0;
return d;
}
//求解a关于模上m的逆元,返回-1表示逆元不存在
ll mod_inverse(ll a, ll m) {
ll x, y, d = extgcd(a, m, x, y);
return d == 1 ? (m + x % m) % m : -1;
}
//计算n! mod pk的部分值 pk为pi的ki次方
//算出的答案不包括pi的幂的那一部分
ll Mul(ll n, ll pi, ll pk) {
if(!n) return 1;
ll ans = 1;
if(n / pk) {
for(ll i=2; i<=pk; i++) //求出循环节乘积
if(i % pi) ans = ans * i % pk;
ans = pow(ans, n / pk, pk); //循环节次数为n / pk
}
for(ll i=2; i<=n%pk; i++)
if(i % pi) ans = ans * i % pk;
return ans * Mul(n / pi, pi, pk) % pk; //递归求解
}
//计算组合数C(n, m) mod pk的值 pk为pi的ki次方
ll C(ll n, ll m, ll p, ll pi, ll pk) {
if(m > n) return 0;
ll a = Mul(n, pi, pk), b = Mul(m, pi, pk), c = Mul(n - m, pi, pk);
ll k = 0, ans; //k为pi的幂值
for(ll i=n; i; i/=pi) k += i / pi;
for(ll i=m; i; i/=pi) k -= i / pi;
for(ll i = n - m; i; i /= pi) k -= i / pi;
ans = a * mod_inverse(b, pk) % pk * mod_inverse(c, pk) % pk * pow(pi, k, pk) % pk; //ans就是n! mod pk的值
ans = ans * (p / pk) % p * mod_inverse(p / pk, pk) % p; //此时用剩余定理合并解
return ans;
}
ll Lucas(ll n, ll m, ll p) {
ll x = p, ans = 0;
for(ll i=2; i<=p; i++) {
if(x % i == 0) {
ll pk = 1;
while(x % i == 0) pk *= i, x /= i;
ans = (ans + C(n, m, p, i, pk)) % p;
}
}
return ans;
}
参考:
http://www.cnblogs.com/fzl194/p/9095177.html
https://blog.csdn.net/u013269631/article/details/43485189