中国剩余定理
中国剩余定理,Chinese Remainder Theorem,又称孙子定理,给出了一元线性同余方程组的有解判定条件,并用构造法给出了通解的具体形式。
现
在
有
方
程
组
:
(
S
)
:
{
x
≡
a
1
(
m
o
d
m
1
)
x
≡
a
2
(
m
o
d
m
2
)
.
.
.
x
≡
a
n
(
m
o
d
m
n
)
中
国
剩
余
定
理
指
出
:
若
∀
i
,
j
,
1
≤
i
<
j
≤
n
,
i
,
j
∈
Z
,
都
有
g
c
d
(
m
i
,
m
j
)
=
1
,
则
对
任
意
整
数
:
a
1
,
a
2
,
.
.
.
,
a
n
,
方
程
组
(
S
)
均
有
解
,
且
通
解
可
以
用
如
下
方
法
构
造
。
设
M
=
∏
i
=
1
n
m
i
,
并
设
M
i
=
M
m
i
,
∀
i
∈
{
1
,
2
,
.
.
.
,
n
}
,
设
t
i
=
M
i
−
1
(
m
o
d
m
i
)
,
则
方
程
通
解
为
:
x
=
k
M
+
∑
i
=
1
n
a
i
t
i
M
i
,
k
∈
Z
。
\begin{aligned} &现在有方程组:\\ &(S):\begin{cases} x\equiv a_1(mod\space m_1)\\ x\equiv a_2(mod\space m_2)\\ \space\space\space\space. \\ \space\space\space\space. \\ \space\space\space\space. \\ x\equiv a_n(mod\space m_n)\\ \end{cases}\\ &中国剩余定理指出:若\forall i,j,1\le i<j\le n,i,j\in Z,都有gcd(m_i,m_j)=1,\\ &则对任意整数:a_1,a_2,...,a_n,方程组(S)均有解,且通解可以用如下方法构造。\\ &设M=\prod_{i=1}^n m_i,并设M_i={M\over m_i},\forall i\in\{1,2,...,n\},\\ &设t_i=M_i^{-1}(mod\space m_i),则方程通解为:x=kM+\sum_{i=1}^n a_it_iM_i,k\in Z。\\ \end{aligned}
现在有方程组:(S):⎩⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎧x≡a1(mod m1)x≡a2(mod m2) . . .x≡an(mod mn)中国剩余定理指出:若∀i,j,1≤i<j≤n,i,j∈Z,都有gcd(mi,mj)=1,则对任意整数:a1,a2,...,an,方程组(S)均有解,且通解可以用如下方法构造。设M=i=1∏nmi,并设Mi=miM,∀i∈{1,2,...,n},设ti=Mi−1(mod mi),则方程通解为:x=kM+i=1∑naitiMi,k∈Z。
下面给出解的正确性证明:
∵
对
∀
i
,
j
,
1
≤
i
<
j
≤
n
,
i
,
j
∈
Z
,
g
c
d
(
m
i
,
m
j
)
=
1
∴
g
c
d
(
m
i
,
M
i
)
=
1
说
明
∃
t
i
,
使
得
t
i
M
i
≡
1
(
m
o
d
m
i
)
又
a
i
t
i
M
i
≡
a
i
⋅
1
≡
a
i
(
m
o
d
m
i
)
,
且
对
∀
i
,
j
∈
{
1
,
2
,
.
.
.
,
n
}
,
i
≠
j
,
a
i
t
i
M
i
≡
0
(
m
o
d
m
j
)
∴
对
∀
i
∈
{
1
,
2
,
.
.
,
n
}
,
x
0
=
∑
j
=
1
n
a
j
t
j
M
j
=
a
i
t
i
M
i
+
∑
j
=
1
,
j
≠
i
n
a
j
t
j
M
j
≡
a
i
t
i
M
i
+
∑
j
=
1
,
j
≠
i
n
0
(
m
o
d
m
i
)
说
明
x
0
是
方
程
组
的
一
个
解
假
设
x
1
,
x
2
都
是
方
程
组
的
解
,
那
么
∀
i
∈
{
1
,
2
,
.
.
,
n
}
,
x
1
−
x
2
≡
0
(
m
o
d
m
i
)
又
对
∀
i
,
j
,
1
≤
i
<
j
≤
n
,
i
,
j
∈
Z
,
g
c
d
(
m
i
,
m
j
)
=
1
,
∴
(
x
1
−
x
2
)
%
M
=
(
x
1
−
x
2
)
%
(
∏
i
=
1
n
m
i
)
=
0
∴
∃
k
∈
Z
,
x
1
−
x
2
=
k
M
,
∴
方
程
通
解
为
:
x
=
k
M
+
∑
i
=
1
n
a
i
t
i
M
i
,
k
∈
Z
\begin{aligned} &∵对\forall i,j,1\le i<j\le n,i,j\in Z,gcd(m_i,m_j)=1∴gcd(m_i,M_i)=1 \\ &说明\exist t_i,使得t_iM_i\equiv1(mod\space m_i)\\ &又a_it_iM_i\equiv a_i\cdot1\equiv a_i(mod\space m_i),且对\forall i,j\in\{1,2,...,n\},i\ne j,a_it_iM_i\equiv0(mod\space m_j)\\ &∴对\forall i\in\{1,2,..,n\},x_0=\sum_{j=1}^n a_jt_jM_j=a_it_iM_i+\sum_{j=1,j\ne i}^n a_jt_jM_j\equiv a_it_iM_i+\sum_{j=1,j\ne i}^n0(mod\space m_i)\\ &说明x_0是方程组的一个解\\ &假设x_1,x_2都是方程组的解,那么\forall i\in \{1,2,..,n\},x_1-x_2\equiv0(mod\space m_i)\\ &又对\forall i,j,1\le i<j\le n,i,j\in Z,gcd(m_i,m_j)=1,∴(x_1-x_2)\%M=(x_1-x_2)\%(\prod_{i=1}^n m_i)=0\\ &∴\exist k\in Z,x_1-x_2=kM,∴方程通解为:x=kM+\sum_{i=1}^n a_it_iM_i,k\in Z \end{aligned}
∵对∀i,j,1≤i<j≤n,i,j∈Z,gcd(mi,mj)=1∴gcd(mi,Mi)=1说明∃ti,使得tiMi≡1(mod mi)又aitiMi≡ai⋅1≡ai(mod mi),且对∀i,j∈{1,2,...,n},i̸=j,aitiMi≡0(mod mj)∴对∀i∈{1,2,..,n},x0=j=1∑najtjMj=aitiMi+j=1,j̸=i∑najtjMj≡aitiMi+j=1,j̸=i∑n0(mod mi)说明x0是方程组的一个解假设x1,x2都是方程组的解,那么∀i∈{1,2,..,n},x1−x2≡0(mod mi)又对∀i,j,1≤i<j≤n,i,j∈Z,gcd(mi,mj)=1,∴(x1−x2)%M=(x1−x2)%(i=1∏nmi)=0∴∃k∈Z,x1−x2=kM,∴方程通解为:x=kM+i=1∑naitiMi,k∈Z
扩展中国剩余定理
在一般情况下,要求任两个数互质这个条件太苛刻了,CRT派不上用场,我们需要一个更具普遍性的结论,这就是EX-CRT。虽然是称为EX-CRT,但这个定理并没有直接用到CRT的结论。
我
们
单
独
考
虑
方
程
组
的
前
两
个
式
子
组
成
的
同
余
方
程
组
S
′
:
{
x
≡
a
1
(
m
o
d
m
1
)
x
≡
a
2
(
m
o
d
m
2
)
我
们
设
整
数
K
1
,
K
2
满
足
x
=
K
1
m
1
+
a
1
,
x
=
K
2
m
2
+
a
2
,
那
么
有
K
1
m
1
+
a
1
=
K
2
m
2
+
a
2
,
即
m
1
K
1
−
m
2
K
2
=
a
2
−
a
1
,
根
据
E
X
G
C
D
,
方
程
在
g
c
d
(
m
1
,
m
2
)
∣
(
a
2
−
a
1
)
时
有
解
把
由
E
X
G
C
D
求
得
的
特
解
记
为
k
1
,
k
2
,
设
S
’
的
一
个
解
为
x
0
,
那
么
有
:
{
x
0
=
a
1
+
k
1
×
a
2
−
a
1
g
c
d
(
m
1
,
m
2
)
×
m
1
x
0
=
a
2
+
k
2
×
a
2
−
a
1
g
c
d
(
m
1
,
m
2
)
×
m
2
这
样
我
们
就
得
到
了
S
′
的
一
个
解
x
0
,
怎
么
求
出
它
的
通
解
呢
?
\begin{aligned} &我们单独考虑方程组的前两个式子组成的同余方程组S':\\ &\begin{cases} x\equiv a_1(mod\space m_1)\\ x\equiv a_2(mod\space m_2)\\ \end{cases}\\ &我们设整数K_1,K_2满足x=K_1m_1+a_1,x=K_2m_2+a_2,那么有K_1m_1+a_1=K_2m_2+a_2,\\ &即m_1K_1-m_2K_2=a_2-a_1,根据EXGCD,方程在gcd(m_1,m_2)|(a_2-a_1)时有解\\ &把由EXGCD求得的特解记为k_1,k_2,设S’的一个解为x_0,那么有:\\ &\begin{cases} x_0=a_1+k_1\times{a_2-a_1\over gcd(m_1,m_2)}\times m_1\\ x_0=a_2+k_2\times{a_2-a_1\over gcd(m_1,m_2)}\times m_2\\ \end{cases}\\ &这样我们就得到了S'的一个解x_0,怎么求出它的通解呢?\\ \end{aligned}
我们单独考虑方程组的前两个式子组成的同余方程组S′:{x≡a1(mod m1)x≡a2(mod m2)我们设整数K1,K2满足x=K1m1+a1,x=K2m2+a2,那么有K1m1+a1=K2m2+a2,即m1K1−m2K2=a2−a1,根据EXGCD,方程在gcd(m1,m2)∣(a2−a1)时有解把由EXGCD求得的特解记为k1,k2,设S’的一个解为x0,那么有:{x0=a1+k1×gcd(m1,m2)a2−a1×m1x0=a2+k2×gcd(m1,m2)a2−a1×m2这样我们就得到了S′的一个解x0,怎么求出它的通解呢?
假 设 S ′ 存 在 两 个 解 x 1 , x 2 ( x 1 < x 2 ) , 由 于 x 1 , x 2 均 满 足 S ′ , 则 : ∃ σ 1 , σ 2 ∈ Z , 满 足 : { x 2 = x 1 + σ 1 × m 1 x 2 = x 1 + σ 2 × m 2 显 然 σ 1 × m 1 = σ 2 × m 2 , 设 d = g c d ( m 1 , m 2 ) , n 1 = m 1 d , n 2 = m 2 d 那 么 上 式 ⇔ σ 1 × n 1 d = σ 2 × n 2 d ⇔ σ 1 × n 1 = σ 2 × n 2 ∴ n 1 ∣ ( σ 2 × n 2 ) 又 由 定 义 可 知 , g c d ( n 1 , n 2 ) = 1 ∴ n 1 ∣ σ 2 , 也 即 ( n 1 n 2 ) ∣ ( σ 2 × n 2 ) → ( n 1 × n 2 d ) ∣ ( σ 2 × n 2 d ) → ( n 1 × n 2 d ) ∣ ( σ 2 × m 2 ) → ( n 1 × n 2 d ) ∣ ( x 2 − x 1 ) ( 由 x 2 = x 1 + σ 2 × m 2 可 得 ) n 1 × n 2 d = n 1 d × n 2 d d = m 1 m 2 g c d ( m 1 , m 2 ) = l c m ( m 1 , m 2 ) 由 此 我 们 得 到 了 S ’ 任 两 解 之 间 的 关 系 : l c m ( m 1 , m 2 ) ∣ ( x 2 − x 1 ) \begin{aligned} &假设S'存在两个解x_1,x_2(x_1<x_2),由于x_1,x_2均满足S',则:\\ &\exist \sigma_1,\sigma_2\in Z,满足: \begin{cases} x_2=x_1+\sigma_1\times m_1\\ x_2=x_1+\sigma_2\times m_2\\ \end{cases}\\ &显然\sigma_1\times m_1=\sigma_2\times m_2,设d=gcd(m_1,m_2),n_1={m_1\over d},n_2={m_2\over d}\\ &那么上式\Lrarr \sigma_1\times n_1d=\sigma_2\times n_2d\Lrarr \sigma_1\times n_1=\sigma_2\times n_2\space∴n_1|(\sigma_2\times n_2)\\ &又由定义可知,gcd(n_1,n_2)=1\space ∴n_1|\sigma_2,也即(n_1n_2)|(\sigma_2\times n_2)\rarr (n_1\times n_2d)|(\sigma_2\times n_2d)\\ &\rarr (n_1\times n_2d)|(\sigma_2\times m_2)\rarr (n_1\times n_2d)|(x_2-x_1)(由x_2=x_1+\sigma_2\times m_2可得)\\ &n_1\times n_2d={n_1d\times n_2d\over d}={m_1m_2\over gcd(m_1,m_2)}=lcm(m_1,m_2)\\ &由此我们得到了S’任两解之间的关系:lcm(m_1,m_2)|(x_2-x_1)\\ \end{aligned} 假设S′存在两个解x1,x2(x1<x2),由于x1,x2均满足S′,则:∃σ1,σ2∈Z,满足:{x2=x1+σ1×m1x2=x1+σ2×m2显然σ1×m1=σ2×m2,设d=gcd(m1,m2),n1=dm1,n2=dm2那么上式⇔σ1×n1d=σ2×n2d⇔σ1×n1=σ2×n2 ∴n1∣(σ2×n2)又由定义可知,gcd(n1,n2)=1 ∴n1∣σ2,也即(n1n2)∣(σ2×n2)→(n1×n2d)∣(σ2×n2d)→(n1×n2d)∣(σ2×m2)→(n1×n2d)∣(x2−x1)(由x2=x1+σ2×m2可得)n1×n2d=dn1d×n2d=gcd(m1,m2)m1m2=lcm(m1,m2)由此我们得到了S’任两解之间的关系:lcm(m1,m2)∣(x2−x1)
由 解 的 关 系 有 x 2 = x 1 + k ⋅ l c m ( m 1 , m 2 ) , k ∈ Z , 结 合 之 前 得 到 的 特 解 x 0 , 可 以 得 出 S ′ 的 通 解 X : X = x 0 + k ⋅ l c m ( m 1 , m 2 ) , k ∈ Z 上 式 又 可 以 写 成 X ≡ x 0 ( m o d l c m ( m 1 , m 2 ) ) , 这 样 , 我 们 就 把 S ′ 转 化 为 了 一 条 同 余 式 对 于 n 条 同 余 式 , 只 需 逐 条 合 并 即 可 。 \begin{aligned} &由解的关系有x_2=x_1+k\cdot lcm(m_1,m_2),k\in Z,结合之前得到的特解x_0,可以得出S'的通解X:\\ &X=x_0+k\cdot lcm(m_1,m_2),k\in Z\\ &上式又可以写成X\equiv x_0(mod\space lcm(m_1,m_2)),这样,我们就把S'转化为了一条同余式\\ &对于n条同余式,只需逐条合并即可。 \end{aligned} 由解的关系有x2=x1+k⋅lcm(m1,m2),k∈Z,结合之前得到的特解x0,可以得出S′的通解X:X=x0+k⋅lcm(m1,m2),k∈Z上式又可以写成X≡x0(mod lcm(m1,m2)),这样,我们就把S′转化为了一条同余式对于n条同余式,只需逐条合并即可。
代码如下:
typedef long long ll;
const int maxn = 111;
// m为模数组,a为余数数组,0~n-1
ll m[maxn], a[maxn];
ll exgcd(ll a, ll b, ll &x, ll &y) {
if (b == 0) {
x = 1; y = 0;
return a;
}
ll ans = exgcd(b, a % b, y, x);
y -= a / b * x;
return ans;
}
ll excrt() {
ll lcm = m[0], last_a = a[0];
for(int i = 1; i < n; i++) {
ll lcm_a = ((a[i] - last_a) % m[i] + m[i]) % m[i];
ll k = lcm, x, y;
ll gcd = exgcd(lcm, m[i], x, y);
ll mod = m[i] / gcd;
x = (x * lcm_a / gcd % mod + mod) % mod;
lcm = lcm / gcd * m[i], last_a = (last_a + k * x) % lcm;
}
return (last_a % lcm + lcm) % lcm;
}
卢卡斯定理
卢卡斯定理是关于组合数和同余的定理,它表明当p为素数时:
C
n
m
=
∏
i
=
0
k
C
n
i
m
i
(
m
o
d
p
)
其
中
,
m
=
m
k
p
k
+
m
k
−
1
p
k
−
1
+
.
.
.
+
m
1
p
+
m
0
n
=
n
k
p
k
+
n
k
−
1
p
k
−
1
+
.
.
.
+
n
1
p
+
n
0
即
m
i
,
n
i
为
m
,
n
的
p
进
制
展
开
中
对
应
次
数
为
i
的
系
数
C_n^m=\prod_{i=0}^k C_{n_i}^{m_i}(mod\space p)\\ 其中,m=m_kp^k+m_{k-1}p^{k-1}+...+m_1p+m_0\\ n=n_kp^k+n_{k-1}p^{k-1}+...+n_1p+n_0\\ 即m_i,n_i为m,n的p进制展开中对应次数为i的系数\\
Cnm=i=0∏kCnimi(mod p)其中,m=mkpk+mk−1pk−1+...+m1p+m0n=nkpk+nk−1pk−1+...+n1p+n0即mi,ni为m,n的p进制展开中对应次数为i的系数
因为当m>n时,二项式系数为0,那么二项式系数即组合数能被p整除等价于在p进制下,存在某一位m的数值大于对应的n的数值。
基于母函数可以简单证明这个定理。
∵
无
论
p
是
质
数
还
是
合
数
,
对
∀
i
∈
N
,
0
<
i
<
p
,
都
有
C
p
i
=
p
!
i
!
(
p
−
i
)
!
∴
在
母
函
数
中
,
对
于
素
数
p
,
(
1
+
x
)
p
≡
1
+
x
p
(
m
o
d
p
)
运
用
数
学
归
纳
法
可
以
得
到
,
对
∀
i
∈
N
,
(
1
+
x
)
p
i
≡
1
+
x
p
i
(
m
o
d
p
)
又
对
∀
t
∈
N
以
及
素
数
p
,
把
t
表
示
为
p
进
制
数
有
:
t
=
∑
i
=
0
k
t
i
p
i
那
么
,
把
m
,
n
都
用
p
进
制
表
示
,
有
∑
m
=
0
n
(
C
n
m
⋅
x
m
)
=
(
1
+
x
)
n
=
∏
i
=
0
k
[
(
1
+
x
)
p
i
]
m
i
≡
∏
i
=
0
k
(
1
+
x
p
i
)
m
i
=
∏
i
=
0
k
(
∑
m
i
=
0
n
i
C
n
i
m
i
⋅
x
m
i
p
i
)
=
∏
i
=
0
k
(
∑
m
i
=
0
p
−
1
C
n
i
m
i
⋅
x
m
i
p
i
)
=
∑
m
=
0
n
[
(
∏
i
=
0
k
C
n
i
m
i
)
⋅
x
m
]
(
m
o
d
p
)
\begin{aligned} &∵无论p是质数还是合数,对\forall i\in N,0<i<p,都有C_p^i={p!\over i!(p-i)!}\\ &∴在母函数中,对于素数p,(1+x)^p\equiv1+x^p(mod\space p)\\ &运用数学归纳法可以得到,对\forall i\in N,(1+x)^{p^i} \equiv1+x^{p^i} (mod\space p)\\ &又对\forall t\in N以及素数p,把t表示为p进制数有:t=\sum_{i=0}^kt_ip^i\\ &那么,把m,n都用p进制表示,有\\ &\space\space\space\space\sum_{m=0}^n\left(C_n^m\cdot x^m\right)\\ &=(1+x)^n=\prod_{i=0}^k\left[(1+x)^{p^i}\right]^{m_i}\\ &\equiv\prod_{i=0}^k\left(1+x^{p^i}\right)^{m_i} =\prod_{i=0}^k\left(\sum_{m_i=0}^{n_i}C_{n_i}^{m_i}\cdot x^{m_ip^i}\right)\\ &=\prod_{i=0}^k\left(\sum_{m_i=0}^{p-1}C_{n_i}^{m_i}\cdot x^{m_ip^i}\right) =\sum_{m=0}^n\left[\left(\prod_{i=0}^kC_{n_i}^{m_i}\right)\cdot x^m\right] (mod\space p) \end{aligned}
∵无论p是质数还是合数,对∀i∈N,0<i<p,都有Cpi=i!(p−i)!p!∴在母函数中,对于素数p,(1+x)p≡1+xp(mod p)运用数学归纳法可以得到,对∀i∈N,(1+x)pi≡1+xpi(mod p)又对∀t∈N以及素数p,把t表示为p进制数有:t=i=0∑ktipi那么,把m,n都用p进制表示,有 m=0∑n(Cnm⋅xm)=(1+x)n=i=0∏k[(1+x)pi]mi≡i=0∏k(1+xpi)mi=i=0∏k(mi=0∑niCnimi⋅xmipi)=i=0∏k(mi=0∑p−1Cnimi⋅xmipi)=m=0∑n[(i=0∏kCnimi)⋅xm](mod p)
代码如下:
typedef long long ll;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 100;
void init() {
F[0] = 1;
for(int i = 2; i < maxn; i++)
F[i] = i * F[i - 1] % mod;
}
ll qpow(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % mod;
b >>= 1; a = a * a % mod;
}
return ans;
}
ll lucas(ll N, ll M) {
ll ans = 1;
while(N & M) {
ll n = N % mod, m = M % mod;
if(n < m) return 0;
ans = ans * F[a] % mod * qpow(F[m] * F[n - m] % mod, mod - 2) % mod;
N /= p; M /= p;
}
return ans;
}
扩展卢卡斯定理
卢卡斯定理同样不能处理模数不是素数的情况,这时便需要扩展卢卡斯定理。我们一步步分析如何求解模数不是素数的组合数问题。
代码和推导部分参考了这篇博客。
首
先
,
我
们
要
解
决
的
问
题
是
求
C
n
m
%
p
,
其
中
p
不
一
定
是
素
数
。
对
于
非
素
数
,
我
们
首
先
会
联
想
到
质
因
分
解
后
结
合
C
R
T
解
决
问
题
。
假
设
分
解
得
到
t
个
质
数
,
质
数
p
i
对
应
的
个
数
为
k
i
,
对
p
质
因
分
解
有
p
=
∏
i
=
1
t
p
i
k
i
。
显
然
对
∀
i
,
j
,
1
≤
i
<
j
≤
t
,
g
c
d
(
p
i
k
i
,
p
j
k
j
)
=
1
,
假
设
对
∀
i
∈
[
1
,
t
]
,
我
们
求
出
了
a
i
=
C
n
m
%
p
i
k
i
,
那
么
我
们
可
以
得
到
同
余
方
程
组
S
:
S
:
{
C
n
m
≡
a
1
(
m
o
d
p
1
k
1
)
C
n
m
≡
a
2
(
m
o
d
p
2
k
2
)
.
.
.
C
n
m
≡
a
t
(
m
o
d
p
t
k
t
)
这
时
我
们
便
可
以
套
用
C
R
T
解
决
问
题
,
那
么
问
题
便
转
化
为
如
何
求
解
C
n
m
%
p
i
k
i
。
\begin{aligned} &首先,我们要解决的问题是求C_n^m\%p,其中p不一定是素数。\\ &对于非素数,我们首先会联想到质因分解后结合CRT解决问题。\\ &假设分解得到t个质数,质数p_i对应的个数为k_i,对p质因分解有p=\prod_{i=1}^tp_i^{k_i}。\\ &显然对\forall i,j,1\le i<j\le t,gcd(p_i^{k_i},p_j^{k_j})=1,假设对\forall i\in[1,t],我们求出了a_i=C_n^m\%p_i^{k_i},\\ &那么我们可以得到同余方程组S:\\ &S:\begin{cases} C_n^m\equiv a_1(mod\space p_1^{k_1})\\ C_n^m\equiv a_2(mod\space p_2^{k_2})\\ \space\space\space\space\space\space\space.\\ \space\space\space\space\space\space\space.\\ \space\space\space\space\space\space\space.\\ C_n^m\equiv a_t(mod\space p_t^{k_t})\\ \end{cases}\\ &这时我们便可以套用CRT解决问题,那么问题便转化为如何求解C_n^m\%p_i^{k_i}。 \end{aligned}
首先,我们要解决的问题是求Cnm%p,其中p不一定是素数。对于非素数,我们首先会联想到质因分解后结合CRT解决问题。假设分解得到t个质数,质数pi对应的个数为ki,对p质因分解有p=i=1∏tpiki。显然对∀i,j,1≤i<j≤t,gcd(piki,pjkj)=1,假设对∀i∈[1,t],我们求出了ai=Cnm%piki,那么我们可以得到同余方程组S:S:⎩⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎧Cnm≡a1(mod p1k1)Cnm≡a2(mod p2k2) . . .Cnm≡at(mod ptkt)这时我们便可以套用CRT解决问题,那么问题便转化为如何求解Cnm%piki。
现 在 我 们 要 求 的 是 C n m % p k , 其 中 p 是 素 数 。 又 C n m = n ! m ! ( n − m ) ! , 显 然 需 要 求 出 m ! 和 ( n − m ) ! 关 于 模 p k 的 逆 元 , 但 考 虑 到 这 些 项 中 可 能 包 含 p ( 含 有 p 则 不 互 质 , 逆 元 不 存 在 ) , 所 以 需 要 先 提 取 p , 得 到 : C n m = n ! p k n m ! p k m ⋅ ( n − m ) ! p k n − m × p k n − k m − k n − m , 这 里 的 阶 乘 是 指 提 取 之 后 的 结 果 。 这 时 就 可 以 计 算 m ! p k m 和 ( n − m ) ! p k n − m 关 于 p k 的 逆 元 了 。 这 里 , 为 了 形 式 的 统 一 , 同 时 提 取 了 n ! 中 的 p 。 那 么 , 问 题 又 转 化 为 了 如 何 求 n ! % p k 。 \begin{aligned} &现在我们要求的是C_n^m\%p^k,其中p是素数。\\ &又C_n^m={n!\over m!(n-m)!},显然需要求出m!和(n-m)!关于模p^k的逆元,\\ &但考虑到这些项中可能包含p(含有p则不互质,逆元不存在),所以需要先提取p,\\ &得到:C_n^m={{n!\over p^{k_n}}\over{m!\over p^{k_m}}\cdot{(n-m)!\over p^{k_{n-m}}}}\times p^{k_n-k_m-k_{n-m}},这里的阶乘是指提取之后的结果。\\ &这时就可以计算{m!\over p^{k_m}}和{(n-m)!\over p^{k_{n-m}}}关于p^k的逆元了。\\ &这里,为了形式的统一,同时提取了n!中的p。那么,问题又转化为了如何求n!\%p^k。 \end{aligned} 现在我们要求的是Cnm%pk,其中p是素数。又Cnm=m!(n−m)!n!,显然需要求出m!和(n−m)!关于模pk的逆元,但考虑到这些项中可能包含p(含有p则不互质,逆元不存在),所以需要先提取p,得到:Cnm=pkmm!⋅pkn−m(n−m)!pknn!×pkn−km−kn−m,这里的阶乘是指提取之后的结果。这时就可以计算pkmm!和pkn−m(n−m)!关于pk的逆元了。这里,为了形式的统一,同时提取了n!中的p。那么,问题又转化为了如何求n!%pk。
目 标 : 计 算 n ! % p k , p 为 质 数 。 上 一 步 中 提 到 , 我 们 需 要 先 提 取 p 。 提 取 结 果 为 : n ! = p ⌊ n p ⌋ × ⌊ n p ⌋ ! × ∏ i = 1 , i % p ≠ 0 n i 。 第 一 部 分 很 好 理 解 , 对 于 每 一 个 p 的 倍 数 , 都 可 以 提 取 出 一 个 p , 一 共 有 ⌊ n p ⌋ 个 ; 第 二 部 分 为 p 的 倍 数 被 提 取 p 之 后 余 下 的 , 是 一 个 阶 乘 的 形 式 。 显 然 在 n ! 中 , 对 于 p 的 幂 , p 的 个 数 不 止 1 个 , 也 就 是 说 第 二 部 分 仍 然 需 要 提 取 , 这 一 部 分 可 以 递 归 解 决 。 第 三 部 分 是 n ! 剔 除 了 p 的 倍 数 之 后 余 下 的 。 ∵ 对 ∀ i < p k , t ∈ N , 都 有 i ≡ ( i + t ⋅ p k ) ( m o d p k ) ∴ 对 ∀ t ∈ N , ∏ i = 1 , i % p ≠ 0 p k i ≡ ∏ i = 1 , i % p ≠ 0 p k ( i + t ⋅ p k ) ( m o d p k ) 这 也 就 是 说 , 第 三 部 分 其 实 是 存 在 循 环 节 的 , ∏ i = 1 , i % p ≠ 0 p k i 一 共 循 环 了 ⌊ n p k ⌋ 次 。 除 去 循 环 节 的 余 项 长 度 在 p k 之 内 , 直 接 累 乘 即 可 。 \begin{aligned} &目标:计算n!\%p^k,p为质数。上一步中提到,我们需要先提取p。\\ &提取结果为:n!=p^{\lfloor{n\over p}\rfloor}\times {\lfloor{n\over p}\rfloor}!\times \prod_{i=1,i\%p\ne 0}^ni。\\ &第一部分很好理解,对于每一个p的倍数,都可以提取出一个p,一共有{\lfloor{n\over p}\rfloor}个;\\ &第二部分为p的倍数被提取p之后余下的,是一个阶乘的形式。显然在n!中,\\ &对于p的幂,p的个数不止1个,也就是说第二部分仍然需要提取,这一部分可以递归解决。\\ &第三部分是n!剔除了p的倍数之后余下的。\\ &∵对\forall i<p^k,t\in N,都有i\equiv(i+t\cdot p^k)(mod\space p^k)\\ &∴对\forall t\in N,\prod_{i=1,i\%p\ne 0}^{p^k}i\equiv\prod_{i=1,i\%p\ne 0}^{p^k}(i+t\cdot p^k)(mod\space p^k)\\ &这也就是说,第三部分其实是存在循环节的,\prod_{i=1,i\%p\ne 0}^{p^k}i一共循环了\lfloor{n\over p^k}\rfloor次。\\ &除去循环节的余项长度在p^k之内,直接累乘即可。\\ \end{aligned} 目标:计算n!%pk,p为质数。上一步中提到,我们需要先提取p。提取结果为:n!=p⌊pn⌋×⌊pn⌋!×i=1,i%p̸=0∏ni。第一部分很好理解,对于每一个p的倍数,都可以提取出一个p,一共有⌊pn⌋个;第二部分为p的倍数被提取p之后余下的,是一个阶乘的形式。显然在n!中,对于p的幂,p的个数不止1个,也就是说第二部分仍然需要提取,这一部分可以递归解决。第三部分是n!剔除了p的倍数之后余下的。∵对∀i<pk,t∈N,都有i≡(i+t⋅pk)(mod pk)∴对∀t∈N,i=1,i%p̸=0∏pki≡i=1,i%p̸=0∏pk(i+t⋅pk)(mod pk)这也就是说,第三部分其实是存在循环节的,i=1,i%p̸=0∏pki一共循环了⌊pkn⌋次。除去循环节的余项长度在pk之内,直接累乘即可。
完整代码如下:
typedef long long ll;
const int N = 1e6 + 100;
ll n, m, p;
ll qpow(ll a, ll b, ll mod) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % mod;
b >>= 1; a = a * a % mod;
}
return ans;
}
ll fac(ll n, ll p, ll pk) {
if (!n) return 1;
ll ans = 1;
for (int i = 1; i < pk; i++)
if (i % p) ans = ans * i % pk;
ans = qpow(ans, n / pk, pk);
int npk = n % pk;
for (int i = 1; i <= npk; i++)
if (i % p) ans = ans * i % pk;
return ans * fac(n / p, p, pk) % pk;
}
ll exgcd(ll a, ll b, ll &x, ll &y) {
if (b == 0) {
x = 1; y = 0;
return a;
}
ll ans = exgcd(b, a % b, y, x);
y -= a / b * x;
return ans;
}
ll inv(ll a, ll p) {
if(!a) return 0;
int x, y;
exgcd(a, p, x, y);
return (x % p + p) % p;
}
ll C(ll n, ll m, ll p, ll pk) {
if (n < m) return 0;
ll fn = fac(n, p, pk),
fm = fac(m, p, pk),
fn_m = fac(n - m, p, pk),
cnt = 0;
for (ll i = n; i; i /= p)
cnt += i / p;
for (ll i = m; i; i /= p)
cnt -= i / p;
for (ll i = n - m; i; i /= p)
cnt -= i / p;
return fn * inv(fm * fn_m % pk, pk) % pk * qpow(p, cnt, pk) % pk;
}
ll a[N], mod[N]; // a[]是通过卢卡斯分解出来的组合数值,m[]是对应的模数
int cnt; // 质因数的种数
ll CRT() {
ll M = 1, ans = 0;
for (int i = 0; i < cnt; i++)
M *= mod[i];
for (int i = 0; i < cnt; i++)
ans = (ans + a[i] * (M / mod[i]) % M * inv(M / mod[i], mod[i]) % M) % M;
return ans;
}
ll exlucas(ll n, ll m, ll p) {
ll sqrtp = sqrt(p + 0.5);
for (int i = 2; p > 1 && i <= sqrtp; i++) {
ll pk = 1;
while (p % i == 0)
p /= i, pk *= i;
if (pk > 1)
a[cnt] = C(n, m, i, pk), mod[cnt++] = pk;
}
if (p > 1)
a[cnt] = C(n, m, p, p), mod[cnt++] = p;
return CRT();
}