Lucas定理
Lucas定理详述
内容
对于一个组合数C m n C_m^n C m n ,取模一个素数p p p 的值,假设n = a × p + b n=a\times p+b n = a × p + b ,m = c × p + d m=c\times p+d m = c × p + d 有:
C n m ≡ C a c × C b d ( m o d p ) C_n^m≡C_a^c\times C_b^d(\mod p) C n m ≡ C a c × C b d ( m o d p )
证明
先证明一个一会儿要用到的定理:
( 1 + x ) p ≡ 1 + x p ( m o d p ) (1+x)^p≡1+x^p(\mod p) ( 1 + x ) p ≡ 1 + x p ( m o d p )
这里可以用费马小定理加以证明:
由于( 1 + x ) p ≡ ( 1 + x ) ( m o d p ) (1+x)^p≡(1+x)(\mod p) ( 1 + x ) p ≡ ( 1 + x ) ( m o d p )
且x p ≡ x ( m o d p ) x^p≡x(\mod p) x p ≡ x ( m o d p ) 即1 + x p ≡ 1 + x ( m o d p ) 1+x^p≡1+x(\mod p) 1 + x p ≡ 1 + x ( m o d p )
于是得证:( 1 + x ) p ≡ 1 + x p ( m o d p ) (1+x)^p≡1+x^p(\mod p) ( 1 + x ) p ≡ 1 + x p ( m o d p )
然后设n = a × p + b n=a\times p+b n = a × p + b ,m = c × p + d m=c\times p+d m = c × p + d
于是:( 1 + x ) n ≡ ( 1 + x ) a × p + b ( m o d p ) (1+x)^n≡(1+x)^{a\times p+b}(\mod p) ( 1 + x ) n ≡ ( 1 + x ) a × p + b ( m o d p )
即:
( 1 + x ) n ≡ ( 1 + x ) a × p × ( 1 + x ) b ( m o d p ) (1+x)^n≡(1+x)^{a\times p}\times (1+x)^b(\mod p) ( 1 + x ) n ≡ ( 1 + x ) a × p × ( 1 + x ) b ( m o d p )
由之前证明的定理得:
( 1 + x ) a × p ≡ ( 1 + x p ) a ( m o d p ) (1+x)^{a\times p}≡(1+x^p)^a(\mod p) ( 1 + x ) a × p ≡ ( 1 + x p ) a ( m o d p )
即:
( 1 + x ) a × p + b ≡ ( 1 + x p ) a × ( 1 + x ) b ( m o d p ) (1+x)^{a\times p+b}≡(1+x^p)^a\times (1+x)^ b(\mod p) ( 1 + x ) a × p + b ≡ ( 1 + x p ) a × ( 1 + x ) b ( m o d p )
由二项式定理得:
( 1 + x ) a × p + b ≡ ∑ i = 0 i → a ( C a i × x p × i ) × ∑ j = 0 j → b ( C b j × x j ) ( m o d p ) (1+x)^{a\times p+b}≡\displaystyle \sum^{i\to a}_{i=0}(C_a^i\times x^{p\times i})\times \displaystyle \sum^{j\to b}_{j=0}(C_b^j\times x^j)(\mod p) ( 1 + x ) a × p + b ≡ i = 0 ∑ i → a ( C a i × x p × i ) × j = 0 ∑ j → b ( C b j × x j ) ( m o d p )
考虑等号两边x m x^m x m 的系数:
由二项式定理得左边x m x^m x m 的系数为:C n m C_n^m C n m
将右边的式子展开,显然当i,j满足p × i + j = = m p\times i+j==m p × i + j = = m 时为x m x^m x m 的系数,也就是i = = c , j = = d i==c,j==d i = = c , j = = d 时,也就是:
C a c × C b d C_a^c\times C_b^d C a c × C b d
则能得到等式C n m ≡ C a b × C b d ( m o d p ) C_n^m≡C_a^b\times C_b^d(\mod p) C n m ≡ C a b × C b d ( m o d p )
于是定理得到了证明。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <iostream> #include <cmath> #include <cstring> #include <cstdio> #include <algorithm> using namespace std;typedef long long ll;ll fact (ll n,ll mod) { ll res=1 ; for (int i = 1 ; i <= n; ++i) { res=(res*i)%mod; } return res; } void exgcd (ll a,ll b,ll &x,ll &y,ll &d) { if (!b) { d=a; x=1 ; y=0 ; } else { exgcd (b,a%b,y,x,d); y-=x*(a/b); } } ll inv (ll t,ll mod) { ll d,x,y; exgcd (t,mod,x,y,d); return d==1 ?(x%mod+mod)%mod:-1 ; } ll comb (ll n,ll m,ll mod) { if (m<0 ||m>n)return 0 ; return fact (n,mod)*inv (fact (m,mod),mod)%mod*inv (fact (n-m,mod),mod)%mod; } ll lucas (ll n,ll m,ll mod) { return m?lucas (n/mod,m/mod,mod)*comb (n%mod,m%mod,mod)%mod:1 ; }
拓展Lucas定理
考虑如果p不是素数的情况,我们考虑利用唯一分解定理将p分解为若干素数的乘积,于是可以将式子分解为一组方程组,即:
C n m ≡ r 1 ( m o d p 1 ) C_n^m≡r_1(\mod p_1) C n m ≡ r 1 ( m o d p 1 )
C n m ≡ r 2 ( m o d p 2 ) C_n^m≡r_2(\mod p_2) C n m ≡ r 2 ( m o d p 2 )
C n m ≡ r 3 ( m o d p 3 ) C_n^m≡r_3(\mod p_3) C n m ≡ r 3 ( m o d p 3 )
.
.
.
C n m ≡ r k ( m o d p k ) C_n^m≡r_k(\mod p_k) C n m ≡ r k ( m o d p k )
于是这个方程组又让我们想到了中国剩余定理(CRT),于是我们就可以使用Lucas定理把r 1 … r k r_1…r_k r 1 … r k 求出来,再用中国剩余定理求解C n m C_n^m C n m 。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 #include <iostream> #include <cmath> #include <cstring> #include <cstdio> #include <algorithm> #include <vector> using namespace std;typedef long long ll;#define MAXN 15 ll t; ll n,m; ll k; ll a[MAXN]; ll r[MAXN]; ll fj (ll n) { int c=0 ; for (int i=2 ;i<=n;i++) { while (n%i==0 ) { a[c++]=i; n/=i; } } return c; } ll mul (ll a,ll b,ll mod) { ll res=0 ; while (b) { if (b&1 )res=(res+a)%mod; a=(a+a)%mod; b>>=1 ; } return res; } ll fact (ll n,ll mod) { ll res=1 ; for (int i = 1 ; i <= n; ++i) { res=(res*i)%mod; } return res; } void exgcd (ll a,ll b,ll &x,ll &y,ll &d) { if (!b) { d=a; x=1 ; y=0 ; } else { exgcd (b,a%b,y,x,d); y-=x*(a/b); } } ll inv (ll t,ll mod) { ll d,x,y; exgcd (t,mod,x,y,d); return d==1 ?(x%mod+mod)%mod:-1 ; } ll comb (ll n,ll m,ll mod) { if (m<0 ||m>n)return 0 ; return fact (n,mod)*inv (fact (m,mod),mod)%mod*inv (fact (n-m,mod),mod)%mod; } ll lucas (ll n,ll m,ll mod) { return m?lucas (n/mod,m/mod,mod)*comb (n%mod,m%mod,mod)%mod:1 ; } ll china (ll n,ll *d,ll *m) { ll M = 1 , ret = 0 ; for (int i = 0 ; i < n; i ++) M *= m[i]; for (int i = 0 ; i < n; i ++) { ll w = M / m[i]; ret = (ret + mul (w * inv (w, m[i]), d[i], M)) % M; } return (ret + M) % M; } int main () { cin>>t; while (t--) { cin>>n>>m>>k; ll num=fj (k); for (int i = 0 ; i <num; ++i) { r[i]=lucas (n,m,a[i]); } cout<<china (num,r,a)<<endl; } return 0 ; }