题目抽象:有n颗水果树,每科树上有无穷多个水果(同一棵树上的水果相同)。现在要从这n棵树上取不超过m个水果,有多少种取法。
ps:S={n1*a1,n2*a2,n3*a3,……,nn*an}.若m<ni(i=1,2,...n) 则s的m组合=T={m*1,(n-1)*0} = (m+n-1)!/(m!)/(n!)=c(m+n-1,m);
思路:利用一一对应的思想,再增加一棵树。从n+1棵树上取m个水果的方案数。
ans=T={m*1,n*0}=(m+n)!/m!/n!=c(n+m,m);
Lucas定理是用来求 c(n,m) mod p,p是素数的值。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 using namespace std; 7 typedef long long LL; 8 9 void ex_gcd(LL a,LL b,LL &d,LL &x,LL &y) 10 { 11 if(b==0) 12 { 13 x=1;y=0;d=a; 14 } 15 else 16 { 17 ex_gcd(b,a%b,d,y,x); 18 y-=(a/b)*x; 19 } 20 } 21 22 LL inv(LL a,LL m) 23 { 24 LL d,x,y; 25 ex_gcd(a,m,d,x,y); 26 if(d==1) 27 return (x%m+m)%m; //x可能为负数 28 return -1; 29 } 30 31 LL CM(LL n,LL m,LL p) 32 { 33 LL a=1,b=1; 34 if(m>n) 35 return 0; 36 //c(n,m)=c(n,m-1)*(n-m+1)/m; O(m) 求c(n,m) 37 while(m) 38 { 39 a=(a*n)%p; 40 b=(b*m)%p; 41 m--; 42 n--; 43 } 44 return (a*inv(b,p))%p; 45 } 46 47 // Lucas(n,m,p)=c(n%p,m%p)*Lucas(n/p,m/p,p) 48 LL Lucas(LL n,LL m,LL p) 49 { 50 if(m==0) 51 return 1; 52 return (CM(n%p,m%p,p)*Lucas(n/p,m/p,p))%p; 53 } 54 55 int main() 56 { 57 int T; 58 scanf("%d",&T); 59 while(T--) 60 { 61 LL n,m,p; 62 scanf("%lld%lld%lld",&n,&m,&p); 63 printf("%lld\n",Lucas(n+m,m,p)); 64 } 65 return 0; 66 }