@Pinetrie
2019-02-21T21:13:33.000000Z
字数 1146
阅读 868
n个树中取小于等于m个豆子,有多少种取法?
假设n个树中取m个豆子。用隔板法,可以转化为在m个人中插入n-1个人有多少种方法。第一个人可以插入的位置有m+1个,第二个人可以插入的位置有m+2个。那么一共有(m+1)(m+2)...(m+n-1) = C(m+n-1,n-1)(n-1)!。而计算收取豆子时是不考虑树的位置的,计算结果还要除以(n-1)!,因此共有C(n + m - 1,m)种方法。再计算m从0到m,C(n-1,0) + C(n,1) + ...+C(n+m-1,m) = C(n+m,m)。再用lucas定理计算
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100010;
ll n,m,p;
ll f[maxn];
void init()
{
f[0] = 1;
for(int i = 1;i <= p;i++)
{
f[i] = f[i - 1] * i % p;
}
}
ll pow_mod(ll a,ll n,ll p)
{
ll res = 1;
while(n)
{
if(n & 1) res = res * a % p;
a = a * a % p;
n >>= 1;
}
return res;
}
ll comb(ll n,ll m)
{
if(n < m) return 0;
return f[n] * pow_mod(f[m] * f[n - m] % p,p - 2,p) % p;
}
ll lucas(ll n,ll m)
{
if(n < m) return 0;
if(m == 0) return 1;
return comb(n % p,m % p) * lucas(n / p,m / p) % p;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%lld %lld %lld",&n,&m,&p);
init();
printf("%lld\n",lucas(n + m,m));
}
return 0;
}
求不经过对角线的网格路径数,是卡特兰数的模型。既可以在下半部分走,也可以在上半部分走,所以结果要乘2。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll kart[36];
void init()
{
kart[0] = kart[1] = 1;
for(int i = 2;i < 36;i++)
{
for(int j = 0;j < i;j++)
{
kart[i] += kart[j] * kart[i - j - 1];
}
}
}
int main()
{
init();
ll n,cas = 0;
while(scanf("%lld",&n) && n != -1)
{
printf("%lld %lld %lld\n",++cas,n,kart[n] * 2);
}
return 0;
}