Lucas定理
Lucas定理
p
p
p是质数,则
C
n
m
≡
C
n
m
o
d
p
m
m
o
d
p
C
⌊
n
p
⌋
⌊
m
p
⌋
(
m
o
d
p
)
C_n^m\equiv C_{n\ mod\ p}^{m\ mod\ p}C_{\lfloor \frac{n} {p}\rfloor}^{\lfloor \frac{m}{p}\rfloor}(mod\ p)
Cnm≡Cn mod pm mod pC⌊pn⌋⌊pm⌋(mod p)
其中
C
n
m
=
0
(
n
<
m
)
C_{n}^{m}=0(n<m)
Cnm=0(n<m)
另一种形式是
表示
m
,
n
m,n
m,n成
p
p
p进制
n
=
∑
i
=
0
k
n
k
p
k
n=\sum_{i=0}^{k}n_k p^k
n=∑i=0knkpk
m
=
∑
i
=
0
k
m
k
p
k
m=\sum_{i=0}^{k}m_k p^k
m=∑i=0kmkpk
则
C
n
m
≡
(
∏
i
=
0
k
C
n
k
m
k
)
(
m
o
d
p
)
C_{n}^{m}\equiv (\prod_{i=0}^{k}C_{n_k}^{m_k})(\ mod\ p)
Cnm≡(i=0∏kCnkmk)( mod p)
引理
p
p
p是质数,
0
<
f
<
p
0<f<p
0<f<p,则
C
p
f
≡
0
(
m
o
d
p
)
C_{p}^{f}\equiv 0(\ mod\ p)
Cpf≡0( mod p)
证明:
因为
p
p
p是质数,所以
f
!
f!
f!和
(
p
−
f
)
!
(p-f)!
(p−f)!中没有
p
p
p的因子,所以显然成立
证明
设
n
=
s
p
+
q
(
0
<
q
<
p
)
n=sp+q(0<q<p)
n=sp+q(0<q<p)
m
=
t
p
+
r
(
0
<
r
<
p
)
m=tp+r(0<r<p)
m=tp+r(0<r<p)
(
1
+
x
)
n
≡
(
1
+
x
)
s
p
+
q
(
m
o
d
p
)
≡
(
(
1
+
x
)
p
)
s
(
1
+
x
)
q
(
m
o
d
p
)
≡
(
∑
i
=
0
p
C
p
i
x
i
)
s
(
1
+
x
)
q
(
m
o
d
p
)
≡
(
1
+
x
p
)
s
(
1
+
x
)
q
(
m
o
d
p
)
≡
∑
i
=
1
s
C
s
i
x
p
i
∑
j
=
1
q
C
q
j
x
j
(
m
o
d
p
)
\begin{aligned} (1+x)^{n} &\equiv (1+x)^{sp+q}(\ mod\ p)\\ &\equiv ((1+x)^{p})^{s}(1+x)^{q}(\ mod\ p)\\ &\equiv (\sum_{i=0}^{p}C_{p}^{i}x^i)^{s}(1+x)^{q}(\ mod\ p)\\ &\equiv (1+x^{p})^{s}(1+x)^{q}(\ mod\ p)\\ &\equiv \sum_{i=1}^{s}C_{s}^{i}x^{pi}\sum_{j=1}^{q}C_{q}^{j}x^{j}(\ mod\ p) \end{aligned}
(1+x)n≡(1+x)sp+q( mod p)≡((1+x)p)s(1+x)q( mod p)≡(i=0∑pCpixi)s(1+x)q( mod p)≡(1+xp)s(1+x)q( mod p)≡i=1∑sCsixpij=1∑qCqjxj( mod p)
由二项式定理
(
1
+
x
)
s
p
+
q
(1+x)^{sp+q}
(1+x)sp+q中
x
t
p
+
r
x^{tp+r}
xtp+r的系数为
C
s
p
+
q
t
p
+
r
C_{sp+q}^{tp+r}
Csp+qtp+r
对照
x
x
x的系数
{
t
p
=
p
i
r
=
j
⇒
{
t
=
i
r
=
j
\begin{cases} tp=pi\\ r=j\\ \end{cases} \Rightarrow \begin{cases} t=i\\ r=j\\ \end{cases}
{tp=pir=j⇒{t=ir=j
⇒
C
s
p
+
q
t
p
+
r
≡
C
s
t
C
q
r
(
m
o
d
p
)
\Rightarrow C_{sp+q}^{tp+r}\equiv C_{s}^{t}C_{q}^{r}(\ mod\ p)
⇒Csp+qtp+r≡CstCqr( mod p)
代码
其中有几个地方可以改的
比如,在lucas那里,先判断取摸后的会不会
m
>
n
m>n
m>n
还有可以直接预处理阶乘逆元,然后用
C
n
m
=
n
!
m
!
(
n
−
m
)
!
C_{n}^{m}=\frac{n!}{m!(n-m)!}
Cnm=m!(n−m)!n!
反正怎么爽怎么来
#include<iostream>
using namespace std;
typedef long long int ll;
int n, m, p;
//快速幂a^m
ll quickMod(const ll &a,ll m) {
ll base = a, ans = 1;
while (m) {
if (m & 1)
ans = ans*base%p;
base = base*base%p;
m >>= 1;
}
return ans;
}
//费马小定理求逆元
ll modReverse(const ll &a, const ll p) {
return quickMod(a, p - 2);
}
ll c(ll n, ll m) {
if (m > n)
return 0;
ll a = 1, b = 1;
while (m) {
a = a*n%p;
b = b*m%p;
--n;
--m;
}
return a*modReverse(b, p) % p;
}
//Lucas定理
ll Lucas(ll n, ll m) {
if (m == 0)
return 1;
return c(n%p, m%p)*Lucas(n / p, m / p) % p;
}
扩展lucas
C
n
m
m
o
d
p
C_n^m \mathop{mod} p
Cnmmodp
其中
p
p
p不一定是质数
首先质因数分解
p
=
p
1
α
1
p
2
α
2
⋯
p = p_1^{\alpha_1}p_2^{\alpha_2}\cdots
p=p1α1p2α2⋯
求出
a
i
=
C
n
m
m
o
d
p
i
α
i
a_i = C_n^m \mathop{mod} p_i^{\alpha_i}
ai=Cnmmodpiαi
最后用中国剩余定理合并
现在求
a
i
=
C
n
m
m
o
d
p
k
=
n
!
m
!
(
n
−
m
)
!
m
o
d
p
k
a_i = C_n^m \mathop{mod} p^k = \frac{n!}{m! \left(n-m\right)!} \mathop{mod} p^k
ai=Cnmmodpk=m!(n−m)!n!modpk其中
p
p
p是质数
由于
n
!
,
(
n
−
m
)
!
n!,(n-m)!
n!,(n−m)!不一定与
p
p
p互质,所以逆元不一定存在,所以转换一下
n
!
m
!
(
n
−
m
)
!
m
o
d
p
k
=
n
!
p
x
m
!
p
y
(
n
−
m
)
!
p
z
p
x
−
y
−
z
m
o
d
p
k
\frac{n!}{m! \left(n-m\right)!} \mathop{mod} p^k = \frac{\frac{n!}{p^x}}{\frac{m!}{p^y} \frac{\left(n-m\right)!}{p^z}} p^{x-y-z} \mathop{mod} p^k
m!(n−m)!n!modpk=pym!pz(n−m)!pxn!px−y−zmodpk
其中
x
x
x为
n
!
n!
n!中
p
p
p的因数个数,
y
y
y为
m
!
m!
m!中
p
p
p的因数个数,
z
z
z为
(
n
−
m
)
!
(n-m)!
(n−m)!中
p
p
p的因数个数
那么现在问题就是
n
!
p
x
m
o
d
p
k
\frac{n!}{p^x}\mathop{mod} p^k
pxn!modpk
n
!
=
1
⋅
2
⋅
3
⋯
n
=
(
p
⋅
2
p
⋅
3
p
⋯
)
(
1
⋅
2
⋅
3
⋯
)
=
p
⌊
n
p
⌋
(
⌊
n
p
⌋
!
)
∏
i
=
1
i
≢
0
(
m
o
d
p
)
n
i
\begin{aligned} n! &= 1\cdot 2 \cdot 3 \cdots n \\ &=\left(p\cdot 2p \cdot 3p\cdots\right)\left(1\cdot 2\cdot 3\cdots\right)\\ &=p^{\left\lfloor\frac{n}{p}\right\rfloor}\left(\left\lfloor\frac{n}{p}\right\rfloor!\right)\prod_{i=1 \atop i \not\equiv 0 \left(\mathop{mod} p\right)}^{n}i\\ \end{aligned}
n!=1⋅2⋅3⋯n=(p⋅2p⋅3p⋯)(1⋅2⋅3⋯)=p⌊pn⌋(⌊pn⌋!)i≡0(modp)i=1∏ni
举个例子
22
!
=
3
7
(
1
⋅
2
⋯
7
)
(
1
⋅
2
⋅
4
⋅
5
⋅
7
⋅
8
⋅
11
⋅
13
⋅
14
⋅
16
⋅
17
⋅
19
⋅
20
⋅
22
)
22! = 3^7\left(1\cdot 2\cdots 7\right)\left(1\cdot 2\cdot 4 \cdot 5 \cdot 7 \cdot 8 \cdot 11 \cdot 13 \cdot 14 \cdot 16 \cdot 17 \cdot 19 \cdot 20 \cdot 22\right)
22!=37(1⋅2⋯7)(1⋅2⋅4⋅5⋅7⋅8⋅11⋅13⋅14⋅16⋅17⋅19⋅20⋅22)
显然最后一个部分,是有循环节的
1
⋅
2
⋅
4
⋅
5
⋅
7
⋅
8
≡
⋅
11
⋅
13
⋅
14
⋅
16
⋅
17
⋅
19
(
m
o
d
3
2
)
1\cdot 2\cdot 4 \cdot 5 \cdot 7 \cdot 8 \equiv \cdot 11 \cdot 13 \cdot 14 \cdot 16 \cdot 17 \cdot 19 \left(\mathop{mod} 3^2 \right)
1⋅2⋅4⋅5⋅7⋅8≡⋅11⋅13⋅14⋅16⋅17⋅19(mod32)
所以
n
!
=
p
⌊
n
p
⌋
(
⌊
n
p
⌋
!
)
(
∏
i
=
1
i
≢
0
(
m
o
d
p
)
p
k
i
)
⌊
n
p
k
⌋
∏
i
=
⌊
n
p
k
⌋
p
k
i
≢
0
(
m
o
d
p
)
n
i
n! = p^{\left\lfloor\frac{n}{p}\right\rfloor}\left(\left\lfloor\frac{n}{p}\right\rfloor!\right)\left(\prod_{i=1 \atop i \not\equiv 0 \left(\mathop{mod} p\right)}^{p^k}i\right)^{\left\lfloor\frac{n}{p^k}\right\rfloor}\prod_{i=\left\lfloor\frac{n}{p^k}\right\rfloor p^k \atop i \not\equiv 0\left(\mathop{mod} p\right)}^{n}i
n!=p⌊pn⌋(⌊pn⌋!)
i≡0(modp)i=1∏pki
⌊pkn⌋i≡0(modp)i=⌊pkn⌋pk∏ni
然而
⌊
n
p
⌋
!
\left\lfloor\frac{n}{p}\right\rfloor!
⌊pn⌋!可能还有
p
k
p^k
pk的因数,所以要继续递归
定义函数
f
(
n
)
=
n
!
p
k
f\left(n\right) = \frac{n!}{p^k}
f(n)=pkn!
显然
f
(
n
)
=
f
(
⌊
n
p
⌋
)
(
∏
i
=
1
i
≢
0
(
m
o
d
p
)
p
k
i
)
⌊
n
p
k
⌋
∏
i
=
⌊
n
p
k
⌋
p
k
i
≢
0
(
m
o
d
p
)
n
i
f\left(n \right) = f\left(\left\lfloor\frac{n}{p}\right\rfloor\right)\left(\prod_{i=1 \atop i \not\equiv 0 \left(\mathop{mod} p\right)}^{p^k}i\right)^{\left\lfloor\frac{n}{p^k}\right\rfloor}\prod_{i=\left\lfloor\frac{n}{p^k}\right\rfloor p^k \atop i \not\equiv 0\left(\mathop{mod} p\right)}^{n}i
f(n)=f(⌊pn⌋)
i≡0(modp)i=1∏pki
⌊pkn⌋i≡0(modp)i=⌊pkn⌋pk∏ni
边界条件
f
(
0
)
=
1
f(0)=1
f(0)=1
现在要求
p
x
−
y
−
z
p^{x -y -z}
px−y−z
定义函数
g
(
n
)
g\left(n\right)
g(n)为
n
!
n!
n!中
p
p
p的因数个数
类似于
f
f
f,可以得到
g
(
n
)
=
⌊
n
p
⌋
+
g
(
⌊
n
p
⌋
)
g\left(n \right) = \left\lfloor\frac{n}{p}\right\rfloor + g\left(\left\lfloor\frac{n}{p}\right\rfloor\right)
g(n)=⌊pn⌋+g(⌊pn⌋)
所以
a
i
=
f
(
n
)
∗
i
n
v
(
f
(
m
)
)
i
n
v
(
f
(
n
−
m
)
)
g
x
−
y
−
z
(
m
o
d
p
i
α
i
)
a_i = f\left(n\right) * inv\left(f\left(m\right)\right)inv\left(f\left(n-m\right)\right) g^{x-y-z} \left(\mathop{mod} p_i^{\alpha_i}\right)
ai=f(n)∗inv(f(m))inv(f(n−m))gx−y−z(modpiαi)
最后用中国剩余定理合并
x
≡
a
i
(
m
o
d
p
i
α
i
)
x \equiv a_i\left(\mathop{mod} p_i^{\alpha_i}\right)
x≡ai(modpiαi)
代码
const int maxN = 1000000;
typedef long long LL;
LL a[maxN], b[maxN], cnt;
LL gcd(LL a, LL b) {
LL c;
while (b) {
c = a % b;
a = b;
b = c;
}
return a;
}
LL extgcd(LL a, LL b, LL& x, LL& y) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
LL ans = extgcd(b, a % b, y, x);
y -= a / b * x;
return ans;
}
LL inv(LL a, LL p) {
LL x, y;
extgcd(a, p, x, y);
return (x % p + p) % p;
}
LL quick_mul(LL a, LL b, LL c) {
a = (a % c + c) % c;
b = (b % c + c) % c;
LL res = 0;
while (b) {
if (b & 1)res = (res + a) % c;
a = (a + a) % c;
b >>= 1;
}
return res;
}
LL quick_pow(LL a, LL b, LL c) {
LL res = 1;
while (b) {
if (b & 1)res = (res * a) % c;
a = (a * a) % c;
b >>= 1;
}
return res;
}
LL f(LL n, LL p, LL pk) {
if (n == 0) {
return 1;
}
LL ans = 1;
//循环节
for (LL i = 1; i < pk; ++i) {
if (i % p != 0) {
ans = ans * i % pk;
}
}
//循环节的n/pk次方
ans = quick_pow(ans, n / pk, pk);
//余项
for (LL i = n / pk * pk; i <= n; ++i) {
if (i % p != 0) {
ans = i % pk * ans % pk;
}
}
return ans * (f(n / p, p, pk) % pk) % pk;
}
LL g(LL n, LL p) {
if (n < p) {
return 0;
}
return n / p + g(n / p, p);
}
// Cn_m % pk
LL c_pk(LL n, LL m, LL p, LL pk) {
// (n!/ p^x)*inv(m!/p^y) * inv((n-m)!/p^z) * p^{z-y-x} % pk
return f(n, p, pk) * inv(f(m, p, pk), pk) % pk * inv(f(n - m, p, pk), pk) % pk * quick_pow(p, g(n, p) - g(m, p) - g(n - m, p), pk);
}
//中国剩余定理, x=a(mod b) ,n是总共有几个同余方程,M用来接收最后的公倍数
LL china(LL a[], LL b[], LL n, LL& M) {
LL ans = 0, lcm = 1, x = 0, y = 0;
for (LL i = 0; i < n; ++i)lcm *= b[i];
for (LL i = 0; i < n; ++i) {
LL Mi = lcm / b[i];
extgcd(Mi, b[i], x, y);
LL ti = inv(Mi, b[i]);
ans = (ans + a[i] % lcm * ti % lcm * Mi % lcm) % lcm;
}
M = lcm;
//返回最小正整数解
return (ans % lcm + lcm) % lcm;
}
LL exLucas(LL n, LL m, LL p) {
LL temp = p;
//质因数分解
for (LL i = 2; i * i <= temp; ++i) {
if (temp % i == 0) {
LL pk = 1;
while (temp % i == 0) {
pk *= i;
temp /= i;
}
b[cnt] = pk;
a[cnt] = c_pk(n, m, i, pk);
++cnt;
}
}
if (temp > 1) {
b[cnt] = temp;
a[cnt] = c_pk(n, m, temp, temp);
++cnt;
}
LL M;
return china(a, b, cnt, M);
}
例题
hdu3037
#include<iostream>
using namespace std;
typedef long long int ll;
int n, m, p;
//快速幂a^m
ll quickMod(const ll &a,ll m) {
ll base = a, ans = 1;
while (m) {
if (m & 1)
ans = ans*base%p;
base = base*base%p;
m >>= 1;
}
return ans;
}
//费马小定理求逆元
ll modReverse(const ll &a, const ll p) {
return quickMod(a, p - 2);
}
ll c(ll n, ll m) {
if (m > n)
return 0;
ll a = 1, b = 1;
while (m) {
a = a*n%p;
b = b*m%p;
--n;
--m;
}
return a*modReverse(b, p) % p;
}
//Lucas定理
ll Lucas(ll n, ll m) {
if (m == 0)
return 1;
return c(n%p, m%p)*Lucas(n / p, m / p) % p;
}
int main() {
int T;
cin >> T;
while (T--) {
cin >> n >> m >> p;
/*
题目相当于不超过m个球放入n个盒子
m个球放入n个盒子如果盒子不为空,则利用插板法,m-1个空插上n-1个挡板c(m-1,n-1)
如果允许空,则相当于每个盒子先放一个球,然后不允许空,n+m个球放入n个盒子,c(n+m-1,n-1)=c(n+m-1,m)
所以m个球放入n个盒子且允许空的方案个数为c(n+m-1,m)
因为是题目是0-m个,则ans=c(n+0-1,0)+c(n+1-1,1)+...+c(n+m-1,m)
由公式C(n,k) = C(n-1,k)+C(n-1,k-1)得
ans=c(n-1,0)+c(n,1)+c(n+1,2)...c(n+m-1,m)=c(n,0)+c(n,1)+c(n+1,2)+...+c(n+m-1,m)
=c(n+1,1)+c(n+1,2)+...+c(n+m-1,m)
=c(n+m,m)
*/
cout << Lucas(n + m, m) << endl;
}
return 0;
}
洛谷P4720
#include<cstdio>
using namespace std;
const int maxN = 1000000;
typedef long long LL;
LL a[maxN], b[maxN], cnt;
LL gcd(LL a, LL b) {
LL c;
while (b) {
c = a % b;
a = b;
b = c;
}
return a;
}
LL extgcd(LL a, LL b, LL& x, LL& y) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
LL ans = extgcd(b, a % b, y, x);
y -= a / b * x;
return ans;
}
LL inv(LL a, LL p) {
LL x, y;
extgcd(a, p, x, y);
return (x % p + p) % p;
}
LL quick_mul(LL a, LL b, LL c) {
a = (a % c + c) % c;
b = (b % c + c) % c;
LL res = 0;
while (b) {
if (b & 1)res = (res + a) % c;
a = (a + a) % c;
b >>= 1;
}
return res;
}
LL quick_pow(LL a, LL b, LL c) {
LL res = 1;
while (b) {
if (b & 1)res = (res * a) % c;
a = (a * a) % c;
b >>= 1;
}
return res;
}
LL f(LL n, LL p, LL pk) {
if (n == 0) {
return 1;
}
LL ans = 1;
//循环节
for (LL i = 1; i < pk; ++i) {
if (i % p != 0) {
ans = ans * i % pk;
}
}
//循环节的n/pk次方
ans = quick_pow(ans, n / pk, pk);
//余项
for (LL i = n / pk * pk; i <= n; ++i) {
if (i % p != 0) {
ans = i % pk * ans % pk;
}
}
return ans * (f(n / p, p, pk) % pk) % pk;
}
LL g(LL n, LL p) {
if (n < p) {
return 0;
}
return n / p + g(n / p, p);
}
// Cn_m % pk
LL c_pk(LL n, LL m, LL p, LL pk) {
// (n!/ p^x)*inv(m!/p^y) * inv((n-m)!/p^z) * p^{z-y-x} % pk
return f(n, p, pk) * inv(f(m, p, pk), pk) % pk * inv(f(n - m, p, pk), pk) % pk * quick_pow(p, g(n, p) - g(m, p) - g(n - m, p), pk);
}
//中国剩余定理, x=a(mod b) ,n是总共有几个同余方程,M用来接收最后的公倍数
LL china(LL a[], LL b[], LL n, LL& M) {
LL ans = 0, lcm = 1, x = 0, y = 0;
for (LL i = 0; i < n; ++i)lcm *= b[i];
for (LL i = 0; i < n; ++i) {
LL Mi = lcm / b[i];
extgcd(Mi, b[i], x, y);
LL ti = inv(Mi, b[i]);
ans = (ans + a[i] % lcm * ti % lcm * Mi % lcm) % lcm;
}
M = lcm;
//返回最小正整数解
return (ans % lcm + lcm) % lcm;
}
LL exLucas(LL n, LL m, LL p) {
LL temp = p;
//质因数分解
for (LL i = 2; i * i <= temp; ++i) {
if (temp % i == 0) {
LL pk = 1;
while (temp % i == 0) {
pk *= i;
temp /= i;
}
b[cnt] = pk;
a[cnt] = c_pk(n, m, i, pk);
++cnt;
}
}
if (temp > 1) {
b[cnt] = temp;
a[cnt] = c_pk(n, m, temp, temp);
++cnt;
}
LL M;
return china(a, b, cnt, M);
}
int main() {
LL n, m, p;
scanf("%lld%lld%lld", &n, &m, &p);
printf("%lld\n", exLucas(n, m, p));
return 0;
}
相关文章
- java实现第二届蓝桥杯四方定理
- 浅谈压缩感知(十二):压缩感知与奈奎斯特采样定理
- ACID与CAP定理
- 【BZOJ 1016】 [JSOI2008]最小生成树计数(matrix-tree定理做法)
- Dilworth定理
- 留数与留数定理
- 中心极限定理
- 8.2 欧拉定理(图论)
- 一文彻底弄明白深度学习中的前馈神经网络(Feed Forward Neural Network)—— 关于万能逼近定理、激活函数、卷积的本质等
- 【数字信号处理】线性时不变系统 LTI “ 输入 “ 与 “ 输出 “ 之间的关系 ( 线性卷积起点定理 | 左边序列概念 | 推理 )
- HDU1163【九余数定理】【水题】
- 极大极小定理
- HDOJ 4549 M斐波那契数列 费马小定理+矩阵高速幂
- 中国剩余定理
- 中值定理的计算