题目描述
传送门
从n棵不同的树上取不超过M颗豆子(豆子无差异),有多少种取法。
题解
考虑如何求解
x1+x2+...+xn=m
的解的个数
可以用插板法求解。由于原题
xi
可以为0,但是插板法不能为0,那么可以等式两边同时+n
x1+1+x2+1+...+xn+1=n+m
这样就相当于有n+m个物品,将其分成n组的方案数,即
Cn−1n+m−1=Cmn+m−1
那么这道题就是要求
∑i=0mCin+i−1=C0n−1+C1n+C2n+1+...+Cmn+m−1
先把第一项写成
C0n
然后利用
Cji=Cji−1+Cj−1i−1
可以将前两项合并然后继续和后面合并
最后答案就是
Cmn+m
利用Lucas定理可以快速求解
Cmn%p
,阶乘预处理一下就行了
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define LL long long
int T;
LL n,m,Mod,mul[100005];
void calc()
{
mul[0]=1LL;
for (LL i=1;i<=Mod;++i) mul[i]=mul[i-1]*i%Mod;
}
LL fast_pow(LL a,LL p)
{
LL ans=1LL;
for (;p;p>>=1,a=a*a%Mod)
if (p&1)
ans=ans*a%Mod;
return ans;
}
LL inv(LL x)
{
return fast_pow(x,Mod-2)%Mod;
}
LL C(LL n,LL m)
{
if (m>n) return 0LL;
return mul[n]*inv(mul[m]*mul[n-m]%Mod)%Mod;
}
LL lucas()
{
LL ans=1LL;
while (m)
{
ans=ans*C(n%Mod,m%Mod)%Mod;
n/=Mod,m/=Mod;
}
return ans;
}
int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%I64d%I64d%I64d",&n,&m,&Mod);
calc();
n+=m;
printf("%I64d\n",lucas());
}
}