Lucas定理
若
P
P
P为质数
C
n
r
≡
C
⌊
n
/
P
⌋
⌊
r
/
P
⌋
×
C
n
m
o
d
P
r
m
o
d
P
(
m
o
d
P
)
C_n^r\equiv C_{\lfloor n/P\rfloor}^{\lfloor r/P\rfloor}\times C_{n\space mod\space P}^{r\space mod\space P}\space (mod \space P)
Cnr≡C⌊n/P⌋⌊r/P⌋×Cn mod Pr mod P (mod P)
要用生成函数证明(不会,所以不证了)
实现直接递归:
void exgcd(long long a,long long b,long long &x,long long &y)
{
if(b==0)
x=1,y=0;
else
{
long long x1,y1;
exgcd(b,a%b,x1,y1);
x=y1;
y=x1-(a/b)*y1;
}
}
long long inv(long long x,long long p)
{
long long i,t;
exgcd(x,p,i,t);
i=(i%p+p)%p;
return i;
}
long long C(long long n,long long r,long long MOD)
{
if(n<r)
return 0;
if(r==0)
return 1;
long long ans=1LL;
ans=C(n/MOD,r/MOD,MOD);
n%=MOD,r%=MOD;
long long a=1,b=1;
for(int i=n;i>n-r;i--)
a=(a*i)%MOD;
for(int i=1;i<=r;i++)
b=(b*i)%MOD;
ans=(ans*a%MOD*inv(b,MOD))%MOD;
return ans;
}
扩展Lucas定理
可以解决模数 P P P不是质数的组合数取模
将
P
P
P质因数分解:
P
=
p
1
k
1
p
2
k
2
.
.
.
p
t
k
t
P=p_1^{k_1}p_2^{k_2}...p_t^{k_t}
P=p1k1p2k2...ptkt
如果我们求出一下方程中的
a
1
,
a
2
.
.
.
a
t
a_1,a_2...a_t
a1,a2...at,就可以利用中国剩余定理求出
C
n
r
C_n^r
Cnr
{
C
n
r
≡
a
1
(
m
o
d
p
1
k
1
)
C
n
r
≡
a
2
(
m
o
d
p
2
k
2
)
C
n
r
≡
a
3
(
m
o
d
p
3
k
3
)
.
.
.
C
n
r
≡
a
t
(
m
o
d
p
t
k
t
)
\left \{ \begin{array}{c} C_n^r\equiv a_1\space (mod\space p_1^{k_1})\\ C_n^r\equiv a_2\space (mod\space p_2^{k_2})\\ C_n^r\equiv a_3\space (mod\space p_3^{k_3})\\ ...\\ C_n^r\equiv a_t\space (mod\space p_t^{k_t})\\ \end{array} \right .
⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧Cnr≡a1 (mod p1k1)Cnr≡a2 (mod p2k2)Cnr≡a3 (mod p3k3)...Cnr≡at (mod ptkt)
现在来求
C
n
r
≡
a
(
m
o
d
p
k
)
C_n^r\equiv a\space(mod\space p^k)
Cnr≡a (mod pk)
C
n
r
≡
n
!
(
n
−
r
)
!
r
!
(
m
o
d
p
k
)
C_n^r\equiv \frac {n!} {(n-r)!\space r!}\space (mod\space p^k)
Cnr≡(n−r)! r!n! (mod pk)
令
a
≡
n
!
(
m
o
d
p
k
)
a\equiv n!\space(mod\space p^k)
a≡n! (mod pk),
b
≡
r
!
(
m
o
d
p
k
)
b\equiv r!\space(mod\space p^k)
b≡r! (mod pk),
c
≡
(
n
−
r
)
!
(
m
o
d
p
k
)
c\equiv(n-r)!\space(mod\space p^k)
c≡(n−r)! (mod pk)
将组合数分成三个阶乘计算:
C
n
r
≡
a
b
−
1
c
−
1
(
m
o
d
p
k
)
C_n^r\equiv a\space b^{-1}c^{-1}\space(mod\space p^k)
Cnr≡a b−1c−1 (mod pk)
(
b
−
1
b^{-1}
b−1表示逆元)
但此时如果
b
b
b与
p
k
p^k
pk不互质,就无法求出逆元,所以需要把
a
a
a,
b
b
b,
c
c
c中的质因子
p
p
p全部提出来,求了逆元之后再乘回去。
举个例子:计算
19
!
(
m
o
d
3
2
)
19! \space(mod\space 3^2)
19! (mod 32)
19
!
=
1
×
2
×
3
×
4
×
.
.
.
×
19
=
(
1
×
2
×
4
×
5
×
7
×
8
×
10
×
11
×
13
×
14
×
16
×
17
×
19
)
×
3
6
×
(
1
×
2
×
3
×
4
×
5
×
6
)
\begin{aligned} 19!&=1\times 2\times 3\times 4\times ...\times 19\\ &= (1\times 2\times 4\times 5\times 7\times 8\times 10\times 11\times 13\times 14\times 16\times 17\times 19)\times3^6 \times (1\times 2\times 3\times 4\times 5\times 6)\\ \end{aligned}
19!=1×2×3×4×...×19=(1×2×4×5×7×8×10×11×13×14×16×17×19)×36×(1×2×3×4×5×6)
即把阶乘中的
p
p
p倍数提出来,后面
6
!
6!
6!继续递归求解;
第一个括号里的式子有周期性的:
1
×
2
×
4
×
5
×
7
×
8
≡
10
×
11
×
13
×
14
×
16
×
17
(
m
o
d
3
2
)
1\times 2\times 4\times 5\times 7\times 8\equiv 10\times 11\times 13\times 14\times 16\times 17 \space (mod \space 3^2)
1×2×4×5×7×8≡10×11×13×14×16×17 (mod 32)
所以暴力求出一个区间的值
t
t
t,结果乘
t
⌊
19
9
⌋
t^{\lfloor \frac {19} 9 \rfloor}
t⌊919⌋
细节见代码:
long long pow_mod(long long a,long long b,long long p)
{
long long res=1;
while(b)
{
if(b&1LL)
res=(res*a)%p;
b>>=1LL;
a=(a*a)%p;
}
return res;
}
void exgcd(long long a,long long b,long long &x,long long &y)
{
if(b==0)
{
x=1,y=0;
return;
}
exgcd(b,a%b,y,x);
y-=(a/b)*x;
}
long long inv(long long a,long long p)//逆元必须用扩展欧几里得,因为p不为质数
{
long long i,t;
exgcd(a,p,i,t);
i=(i%p+p)%p;
return i;
}
long long Fac(long long N,long long p,long long pk)
{
if(N==0)
return 1;
long long ans=1;
if(N>=pk)//周期性
{
for(long long i=1;i<pk;i++)
if(i%p)
ans=(ans*i)%pk;
ans=pow_mod(ans,N/pk,pk);
}
for(long long i=1;i<=N%pk;i++)//除了周期性的,剩下的几个数
if(i%p)
ans=(ans*i)%pk;
ans=(ans*Fac(N/p,p,pk))%pk;//递归求解
return ans;
}
long long C(long long N,long long R,long long p,long long pk)
{
if(R==0)
return 1;
long long a=Fac(N,p,pk),b=Fac(N-R,p,pk),c=Fac(R,p,pk),k=0,ans;//求出几个阶乘,不包含质因子p
//下面单独计算质因子p的个数
for(long long i=N;i;i/=p)
k+=i/p;
for(long long i=N-R;i;i/=p)
k-=i/p;
for(long long i=R;i;i/=p)
k-=i/p;
ans=a*inv(b,pk)%pk*inv(c,pk)%pk*pow_mod(p,k,pk)%pk;
return ans;
}
long long C(long long N,long long R,long long M)
{
if(N<R)
return 0;
long long ans=0,m=M,temp;
for(long long p=2,pk;p*p<=m;p++)
if(m%p==0)//枚举模数M的因子p
{
pk=1;
while(m%p==0)
m/=p,pk*=p;
temp=C(N,R,p,pk);//求C(N,R)mod p^k
ans=(ans+temp*(M/pk)%M*inv(M/pk,pk)%M)%M;//中国剩余定理
}
if(m!=1)
{
temp=C(N,R,m,m);
ans=(ans+temp*(M/m)%M*inv(M/m,m)%M)%M;
}
return ans;
}