首页 > 代码库 > Lucas定理及其应用

Lucas定理及其应用

Lucas定理这里有详细的证明。

其实就是针对n, m很大时,要求组合数C(n, m) % p, 一般来说如果p <= 10^5,那么就能很方便的将n,m转化为10^5以下这样就可以按照乘法逆元的方法求解。

定义:

C(n, m) = C(n%p, m%p)*C(n/p, m/p) (mod p)

一种比较好理解的证明方式是这样的, 上面资料中有提到,

由p为质数,(1+x)^p = 1+x^p (mod p) p为质数,然后就是下面这幅图的内容了。

将n, m分别表示成p进制,n = n/p*p+a0, m = m/p*p+b0;

 

那么对于上面式子x^m的系数,左右两部分肯定是相等的,左边系数C(n, m) ,  而m = m/p*p+b0, 那么i和j分别对应m/p, 和bo

所以就可以得到证明:C(n, m) = C(n%p, m%p)*C(n/p, m/p) (mod p)。

下面就是具体题目了:

HDU 

 1 #include <iostream> 2 #include <string.h> 3 #include <stdio.h> 4 using namespace std; 5  6 #define N 100010 7  8 long long mod_pow(int a,int n,int p) 9 {10     long long ret=1;11     long long A=a;12     while(n)13     {14         if (n & 1)15             ret=(ret*A)%p;16         A=(A*A)%p;17         n>>=1;18     }19     return ret;20 }21 22 long long factorial[N];23 24 void init(long long p)25 {26     factorial[0] = 1;27     for(int i = 1;i <= p;i++)28         factorial[i] = factorial[i-1]*i%p;29     //for(int i = 0;i < p;i++)30         //ni[i] = mod_pow(factorial[i],p-2,p);31 }32 33 long long Lucas(long long a,long long k,long long p) //求C(n,m)%p p最大为10^5。a,b可以很大!34 {35     long long re = 1;36     while(a && k)37     {38         long long aa = a%p;long long bb = k%p;39         if(aa < bb) return 0; //这个是最后的改动!40         re = re*factorial[aa]*mod_pow(factorial[bb]*factorial[aa-bb]%p,p-2,p)%p;//这儿的求逆不可先处理41         a /= p;42         k /= p;43     }44     return re;45 }46 47 int main()48 {49     int t;50     cin >> t;51     while(t--)52     {53         long long n,m,p;54         cin >> n >> m >> p;55         init(p);56         cout << Lucas(n+m,m,p) << "\n";57     }58     return 0;59 }
View Code

 

Lucas定理及其应用