LOJ

分析

树相等于一个左部点是深度为奇数的点、右部点是深度为偶数的点的二分图。

首先需要在 $n-1$ 个点中选出 $k-1$ 个作为深度为奇数的点($1$ 的深度一定为奇数)。

将深度为奇数的点作为左部点、深度为偶数的点作为右部点,两部分间两两连边,则问题变为求生成树个数。

考虑 Prufer 序列,则左部点出现了 $n-k-1$ 次、右部点出现了 $k-1$ 次,故生成树个数为 $k^{n-k-1}(n-k)^{k-1}$。当然也可以手算基尔霍夫矩阵

故答案为 ${n-1\choose k-1}k^{n-k-1}(n-k)^{k-1}$。

代码

// ====================================
//   author: M_sea
//   website: https://m-sea-blog.com/
// ====================================
#include <bits/stdc++.h>
#define file(x) freopen(#x".in","r",stdin); freopen(#x".out","w",stdout)
using namespace std;
typedef long long ll;

int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

int n,k,mod;
int qpow(int a,int b) { int c=1;
    for (;b;b>>=1,a=1ll*a*a%mod) if (b&1) c=1ll*c*a%mod;
    return c;
}
int fac(int n) { int s=1; for (int i=2;i<=n;++i) s=1ll*s*i%mod; return s; }
int C(int n,int m) {
    if (n<m) return 0;
    return 1ll*fac(n)*qpow(fac(m),mod-2)%mod*qpow(fac(n-m),mod-2)%mod;
}

int main() {
    n=read(),k=read(),mod=read();
    printf("%d\n",1ll*C(n-1,k-1)*qpow(k,n-k-1)%mod*qpow(n-k,k-1)%mod);
    return 0;
}
最后修改:2020 年 06 月 07 日 04 : 20 PM