题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=3037
题意:给你m个相同的bean和n棵不同的树,每棵树可以放也可以不放beans。问有多少种放的方案。
思路:可以转化成m个相同的小球,n+1个不同的盒子的模型。n+1是因为这n棵树可以放不到m个小球,也就相当于一个新的盒子可以用来放小球。
对于这类组合问题,我们可以采用插板法。首先有m个小球,m+1个空位,第一块板子有m+1种插法,继而,有了m+2个空位,第二个板子有m+2种插法,以此类推,第n块板子有m+n种插法。由乘法原理可得,共有(m+1)*(m+2)*......*(m+n)种方法。但由于每块板子是完全相同的,而得到的所有方案数板子是有序的,所以最后要除以n块板子的全排列。故总方案数为C(m+n,n)%p,可以用lucas定理求出。
代码:
#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
ll f[maxn];
void init(ll p) {
f[0] = 1;
for (int i = 1; i <= p; ++i)
f[i] = f[i - 1] * i % p;
}
ll pow_mod(ll a, ll b, ll mod) {
ll ans = 1;
while (b > 0) {
if (b & 1)ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
ll lucas(ll n, ll m, ll p) {
ll ans = 1;
while (n && m) {
ll a = n % p, b = m % p;
if (a < b)return 0;
ans = ans * f[a] % p * pow_mod(f[b] * f[a - b] % p, p - 2, p) % p;
n /= p;
m /= p;
}
return ans;
}
int main() {
int _;
scanf("%d", &_);
while (_--) {
ll n, m, p;
scanf("%lld%lld%lld", &n, &m, &p);
init(p);
printf("%lld\n", lucas(m + n, m, p));
}
return 0;
}