题意:
求在n棵树上摘不超过m颗豆子的方案,结果对p取模。
解析:
题目可以转换成 x1+x2+……+xn=m 有多少组解,m在题中可以取0~m。
利用插板法可以得出 x1+x2+……+xn=m
解的个数为 Cn−1n+m−1=Cmn+m−1 ;则题目解的个数可以转换成求 sum=C0n+m−1+C1n+m−1+C2n+m−1……+Cmn+m−1
利用公式 Crn=Crn−1+Cr−1n−1==>sum=Cmn+m 。
那么答案,就是要求 Cmn+m%p 。
因为n,m很大,这里可以直接套用Lucas定理的模板即可。
关于Lucas定理
Lucas(n,m,p)=C(n%p,m%p,p)∗Lucas(n/p,m/p,p)
//这里可以采用对n分段递归求解
Lucas(x,0,p)=1
将 n,m 分解变小之后问题又转换成了求 (a/b)%p 。
(a/b)%p
可以转换成
a∗Inv(b,p)
Inv(b,p)
为b对p的逆元。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 100005;
ll fac[N];
ll modpow(ll a, ll b, ll MOD) {
ll ret = 1;
while(b) {
if(b&1) ret = (ret*a)%MOD;
a = (a*a)%MOD;
b>>=1;
}
return ret;
}
ll getFactor(ll p) {
fac[0] = 1;
for(int i = 1; i <= p; i++)
fac[i] = (fac[i-1]*i) % p;
}
ll Lucas(ll n, ll m, ll p) {
ll ret=1;
while(n && m) {
ll a = n%p, b = m%p;
if(a<b) return 0;
ret = (ret * fac[a] * modpow(fac[b]*fac[a-b]%p, p-2, p)) % p;
n/=p;
m/=p;
}
return ret;
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
ll n, m, p;
scanf("%I64d%I64d%I64d", &n, &m, &p);
getFactor(p);
printf("%I64d\n",Lucas(n+m,m,p));
}
return 0;
}