hdu3037 Silver Cow Party (Lucas定理 组合数取模)
题意为:将不超过m个豆子放在n棵不同的树上,一共有多少种方法。
题目相当于求n个数的和不超过m的方案数。
如果和恰好等于m,那么就等价于方程x1+x2+...+xn = m的解的个数,利用插板法可以得到方案数为:
(m+1)*(m+2)...(m+n-1) = C(m+n-1,n-1) = C(m+n-1,m)
现在就需要求不大于m的,相当于对i = 0,1...,m对C(n+i-1,i)求和,根据公式C(n,k) = C(n-1,k)+C(n-1,k-1)得
C(n-1,0)+C(n,1)+...+C(n+m-1,m)
= C(n,0)+C(n,1)+C(n+1,2)+...+C(n+m-1,m)
= C(n+m,m)
现在就是要求C(n+m,m) % p,其中p是素数。
然后利用Lucas定理的模板就可以轻松的求得C(n+m,m) % p的值
代码:
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn=100002;
int T;
ll fact[maxn];
ll n,m,p;
void F(ll p)
{
fact[0]=1;
for(int i=1;i<=p;i++)
fact[i]=fact[i-1]*i%p;
}
ll qpow_mod(ll a,ll n,ll b)
{
ll s=1;
while(n)
{
if(n&1)
s=s*a%p;
a=a*a%p;
n>>=1;
}
return s;
}
ll Lucas(ll n,ll m,ll p)
{
ll ans=1;
while(n&&m)
{
ll a=n%p;
ll b=m%p;
if(a<b) return 0;
ans=(ans*fact[a]*qpow_mod(fact[b]*fact[a-b]%p,p-2,p))%p;
n/=p;
m/=p;
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin>>T;
while(T--)
{
cin>>n>>m>>p;
F(p);
cout<<Lucas(n+m,m,p)<<endl;
}
return 0;
}