组合数取模有三种方法
第一种是杨辉三角用数组跑,时间复杂度高
第二种使用逆元法求,适用于m,n较小,而mod较大的情况
第三种是Lucas定理适用于n,m较大的情况;
逆元法
记需要取余的数mod为p
##p要求是质数,不然就GG吧
虽
然
有
C
n
m
=
n
!
m
!
(
n
−
m
)
!
,
但
由
于
取
模
的
性
质
对
于
除
法
不
适
用
虽然有C_n^m=\frac{n!}{m!(n−m)!},但由于取模的性质对于除法不适用
虽然有Cnm=m!(n−m)!n!,但由于取模的性质对于除法不适用
所
以
C
n
m
%
p
≠
(
n
!
%
p
m
!
%
p
(
n
−
m
)
!
%
p
)
%
p
所以C_n^m\%p\neq\left(\frac{n!\%p}{m!\%p(n−m)!\%p}\right)\%p
所以Cnm%p=(m!%p(n−m)!%pn!%p)%p
所以需要把“除法”转换成“乘法”,才能借助取模的性质在不爆long long的情况下计算组合数。这时候就需要用到“逆元”!
逆元:对于a和p,若a*b%p≡1,则称b为a%p的逆元。
对
于
(
a
b
)
%
p
,
假
设
c
为
b
的
逆
元
,
即
b
∗
c
%
p
≡
1
,
那
么
(
a
b
)
%
p
=
(
a
∗
b
∗
c
%
p
b
)
对于\left({a}\over{b}\right)\%p,假设c为b的逆元 ,即b*c\%p\equiv1,那么\left({a}\over{b}\right)\%p=\left({a*b*c\%p}\over{b}\right)
对于(ba)%p,假设c为b的逆元,即b∗c%p≡1,那么(ba)%p=(ba∗b∗c%p)
即
(
a
b
)
%
p
=
(
a
∗
c
%
p
)
=
(
(
a
%
p
)
∗
c
%
p
)
%
p
即\left({a}\over{b}\right)\%p=\left(a*c\%p\right) =\left(\left(a\%p\right)*c\%p\right)\%p
即(ba)%p=(a∗c%p)=((a%p)∗c%p)%p
逆元的求法有三种,一种是扩展欧几里得求逆元,转换成同余方程,一种是线性求逆元,另一种就是当p是质数时强大的费马小定理;
###扩展欧几里得
a与b互质,存在n,m使方程am+bn=gcd(a,b)=1成立
a*m%b+0=1成立
m就是a%b的逆元.
求逆元代码:
long long inv(long long a,long long p)
{
long long x,y;
long long d=extend_gcd(a,p,x,y);
if(d==1) return (x%n+n)%n;
else return -1;
}
long long extend_gcd(long long a,long long b,long long &x,long long &y)
{
if(a==0&&b==0)return -1;
if(b==0)
{
x=1;
y=0;
return a;
}
long long d=extend_gcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
###线性求逆元
//a<p
long long inv(long long a,long long p)
{
if(a==1)
return 1;
return inv(p%a,p)*(p-p/a)%p
}
###费马小定理:
对
于
质
数
a
,
a
p
−
1
%
p
≡
1
,
又
因
为
a
p
−
1
=
a
p
−
2
∗
a
,
所
以
a
p
−
2
是
a
的
逆
元
,
那
样
就
可
以
用
快
速
幂
求
逆
元
了
对于质数a,a^{p-1}\%p\equiv1,又因为a^{p-1}=a^{p-2}*a,所以a^{p-2}是a的逆元,那样就可以用快速幂求逆元了
对于质数a,ap−1%p≡1,又因为ap−1=ap−2∗a,所以ap−2是a的逆元,那样就可以用快速幂求逆元了
对
于
组
合
数
n
!
m
!
(
n
−
m
)
!
%
p
=
(
n
!
m
!
%
p
∗
1
(
n
−
m
)
!
%
p
)
%
p
对于组合数\frac{n!}{m!(n−m)!}\%p=\left(\frac{n!}{m!}\%p*\frac{1}{\left(n-m\right)!}\%p\right)\%p
对于组合数m!(n−m)!n!%p=(m!n!%p∗(n−m)!1%p)%p
首 先 用 费 马 小 定 理 求 m ! 的 逆 元 记 作 m 逆 元 = ( m ! ) p − 2 , 首先用费马小定理求m!的逆元记作m_{逆元}=\left({m!}\right)^{p-2}, 首先用费马小定理求m!的逆元记作m逆元=(m!)p−2, 然 后 求 出 ( n − m ) ! 的 逆 元 记 作 n m 逆 元 = ( ( n − m ) ! ) p − 2 然后求出(n-m)!的逆元记作nm_{逆元}=\left({(n-m)!}\right)^{p-2} 然后求出(n−m)!的逆元记作nm逆元=((n−m)!)p−2 C n m % p = n ! m ! ( n − m ) ! % p = ( n ! m ! % p ∗ 1 ( n − m ) ! % p ) % p = ( ( n ! % p ∗ m 逆 元 % p ) % p ∗ ( 1 ∗ n m 逆 元 % p ) % p ) % p C_n^m\%p=\frac{n!}{m!(n−m)!}\%p=\left(\frac{n!}{m!}\%p*\frac{1}{\left(n-m\right)!}\%p\right)\%p=\left(\left(n!\%p*m_{逆元}\%p\right)\%p*\left(1*nm_{逆元}\%p\right)\%p\right)\%p Cnm%p=m!(n−m)!n!%p=(m!n!%p∗(n−m)!1%p)%p=((n!%p∗m逆元%p)%p∗(1∗nm逆元%p)%p)%p
sdut3895(2017山东省赛C题)就是逆元求组合数的题目,不能用卢卡斯定理,TLE,TLE,TLE…
SDUT3895题目链接
2017山东省赛C题题解
###Lucas定理(大部分情况 p<
1
0
5
10^5
105)证明过程看这里
C
n
m
%
p
=
(
C
n
%
p
m
%
p
%
p
∗
C
n
/
p
m
/
p
%
p
)
%
p
C_n^m\%p=\left(C_{n\%p}^{m\%p}\%p*C_{n/p}^{m/p}\%p\right)\%p
Cnm%p=(Cn%pm%p%p∗Cn/pm/p%p)%p
且
C
n
0
=
1
;
且C_n^0=1;
且Cn0=1;
这样我们就可以用逆元法求出
C
n
%
p
m
%
p
C_{n\%p}^{m\%p}
Cn%pm%p,然后递归求解
C
n
m
%
p
C_n^m\%p
Cnm%p
Lucas定理模板(C(m,n)代表
C
n
m
C_n^m
Cnm)
long long Lucas(long long n,long long m)
{
if(m==0)
return 1;
return Lucas(n/p,m/p)*C(n%p,m%p)%p;
}