卢卡斯定理

求组合数取模的利器——卢卡斯定理。

设C(n,m)表示m个里取n个的方案数。

则有:C(n,m) % p = C(n%p,m%p) * C(n/p,m/p) % p

证明:我不会......

代码实现就很简单了,预处理出所有p以内的阶乘及阶乘逆元。

求C的时候,如果m大于p,利用卢卡斯定理递归求值。

如果m在p以内,直接用阶乘及阶乘逆元求出来。

特别地,如果n>m,C(n,m) = 0 。

下面来一道模板题:洛谷P3807 【模板】卢卡斯定理

 1 #include<cstdio>
 2 #define ll long long
 3 
 4 ll n,m,p,t;
 5 ll fac[100005];
 6 ll inv[100005];
 7 
 8 ll c(ll cn,ll cm)
 9 {
10     if(cm<cn)return 0;
11     if(cm<=p)
12     {
13         return fac[cm]*inv[cn]%p*inv[cm-cn]%p;
14     }else
15     {
16         return c(cn%p,cm%p)*c(cn/p,cm/p)%p;
17     }
18 }
19 
20 int main()
21 {
22     scanf("%lld",&t);
23     while(t--)
24     {
25         scanf("%lld%lld%lld",&n,&m,&p);
26         fac[0]=inv[0]=inv[1]=1;
27         for(int i=1;i<=p;i++)fac[i]=fac[i-1]*i%p;
28         for(int i=2;i<=p;i++)inv[i]=(p-p/i)*inv[p%i]%p;
29         for(int i=2;i<=p;i++)inv[i]=inv[i]*inv[i-1]%p;
30         printf("%lld\n",c(m,n+m));
31     }
32     return 0;
33 }

 

posted @ 2018-09-03 19:27  cervusky  阅读(211)  评论(0编辑  收藏  举报

Contact with me