题面:
给定 n , m n,m n,m求 n n n个节点的 m m m叉树的形态有多少种
范围&性质: 1 ≤ n , m ≤ 127 1\le n,m\le 127 1≤n,m≤127
分析:
- DP做法
当 m m m等于2时就是卡特兰数,详情见卡特兰数定义和递推式
那我们考虑像Catlan数一样枚举每个儿子的大小然后组合起来,所以设 f [ i ] [ j ] f[i][j] f[i][j]表示表示根节点有 i i i个 m m m叉子树,总个数为 j j j的方案数, g [ i ] g[i] g[i]表示用 i i i个点构成一颗 m m m叉树的方案数,转移时相当于往根节点上接一颗 m m m叉树
f [ i ] [ j ] = ∑ g [ k ] × f [ i − 1 ] [ j − k ] f[i][j]=\sum g[k]\times f[i-1][j-k] f[i][j]=∑g[k]×f[i−1][j−k]
为了消掉转移对原有状态的影响,还应该更新 g g g数组
g [ i ] = f [ m ] [ i ] g[i]=f[m][i] g[i]=f[m][i]
复杂度 O ( n 3 ) O(n^3) O(n3)
- 组合做法
我们将每个节点有几个儿子记录下来,按照编号会组成一个序列,序列里的每一项值的大小不会超过 m m m,序列一共有 n n n项,每一个合法的序列一定满足元素之和等于 n − 1 n-1 n−1,也就是说它的组合意义就是从 n ∗ m n*m n∗m个点中选出 n − 1 n-1 n−1个的合法方案数,我们发现按照 d f s dfs dfs序选儿子,每次能选的点会变少(因为已经被选过的点是不能选的)
所以对于所有情况合法的方案占总方案数的 ∏ i = 1 n − 1 i i + 1 = 1 n \prod_{i=1}^{n-1} \frac{i}{i+1}=\frac{1}{n} ∏i=1n−1i+1i=n1
最后总的答案就是 a n s = C ( n ∗ m , n − 1 ) n ans=\frac{C(n*m,n-1)}{n} ans=nC(n∗m,n−1)
代码:
#include<bits/stdc++.h>
using namespace std;
namespace zzc
{
const int mod = 10007;
long long n,m;
long long fac[mod+5],inv[mod+5];
void init()
{
fac[0]=fac[1]=1;
inv[0]=inv[1]=1;
for(int i=2;i<=mod;i++)
{
fac[i]=fac[i-1]*i%mod;
inv[i]=inv[mod%i]*(mod-mod/i)%mod;
}
for(int i=2;i<=mod;i++) inv[i]=inv[i]*inv[i-1]%mod;
}
long long qpow(long long x,long long y)
{
long long res=1;
while(y)
{
if(y&1) res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}
long long C(long long n,long long m)
{
if(m>n) return 0;
return fac[n]*inv[n-m]%mod*inv[m]%mod;
}
long long lucas(long long n,long long m)
{
if(!m) return 1;
return lucas(n/mod,m/mod)*C(n%mod,m%mod)%mod;
}
void work()
{
init();
scanf("%lld%lld",&n,&m);
printf("%lld\n",lucas(n*m,n-1)*qpow(n,mod-2)%mod);
}
}
int main()
{
zzc::work();
return 0;
}