Saving Beans 组合数学之 Lucas定理

                   Saving Beans

题目抽象:有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 }

 

你可能感兴趣的:(bean)