题目大意:求在n棵树保存不超过m个豆子的方法数,结果对p取模。 (n、m<=1000000000,p<100000且为质数)
分析:
由插板法,在n棵树保存i个豆子方案数为C(n+i-1,i)。
不超过m个豆子,则方案数为C(n+0-1,0)+C(n+1-1,0)+……+C(n+m-1,m)。
根据组合数性质:C(n,m)=C(n-1,m-1)+C(n-1,m),可将上式化简为C(n+m,m)
即所求结果为C(n+m,m)
考虑到n、m非常大,而p为10^5内的质数,因而可以使用lucas定理求出答案。
Lucas定理:通俗点来说就是把C(n,m)%p的中n,m化成p进制,然后分别求p进制下,n,m对应位的C(nk,mk)相乘对p取模。
证明如下:
#include<stdio.h> #include<algorithm> using namespace std; typedef long long LL; LL pow(LL a,LL b,LL p) { LL ans=1; while(b) { if(b&1) ans=ans*a%p; a=a*a%p; b>>=1; } return ans; } LL C(LL n,LL m,LL p) { if(m>n||m<0) return 0; if(n-m<m) m=n-m; LL a=1,b=1; for(int i=0;i<m;++i) { a=a*(n-i)%p; b=b*(m-i)%p; } return a*pow(b,p-2,p)%p; } LL Lucas(LL n,LL m,LL p) { LL ans=1; while(n&&m&&ans) { ans=ans*C(n%p,m%p,p)%p; n/=p,m/=p; } return ans; } int main() { int t; LL n,m,p; scanf("%d",&t); while(t--) { scanf("%lld%lld%lld",&n,&m,&p); printf("%lld\n",Lucas(n+m,m,p)); } return 0; }