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 }
时间: 2024-10-14 23:47:57