cychester

BZOJ 1430 小猴打架 - prufer数列

描述

一开始森林里面有N只互不相识的小猴子,它们经常打架,但打架的双方都必须不是好朋友。每次打完架后,打架的双方以及它们的好朋友就会互相认识,成为好朋友。经过$N-1$次打架之后,整个森林的小猴都会成为好朋友。 现在的问题是,总共有多少种不同的打架过程。 比如当$N=3$时,就有{1-2,1-3}{1-2,2-3}{1-3,1-2}{1-3,2-3}{2-3,1-2}{2-3,1-3}六种不同的打架过程。

题解

问题 $=$ 求出$N$个有标号节点的树的个数 $\times$ 连边的顺序。

因为有 $N - 1$条边, 所以连边的顺序就是 $!(N-1)$。

然后需要考虑的就是$N$个有标号节点的树的个数。

我们首先要介绍prufer数列, 传送门

prufer数列的构造方法 :找出度数为1 的节点中标号最小的点$x$,将与它相连的节$y$点录入数列, 再删除$x$。

重复上述过程 , 直到只剩两个点。 这样构造出的数列与树唯一对应。 并且树也唯一对应数列。即数列的个数与树的个数相同。

个数都为$N^{N-2}$

 

最后的答案就是$N^{N - 2} \times !(N - 1)$

 

代码

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 typedef long long ll;
 6 const int mod = 9999991;
 7 
 8 ll ans, n;
 9 
10 ll fpow(ll a,ll p) {
11     ll re = 1;
12     for(; p; p >>= 1, a = a * a % mod) if(p &  1) re = re * a % mod;
13     return re;
14 }
15 
16 int main()
17 {
18     scanf("%lld", &n);
19     ans = fpow(n, n - 2);
20     for(int i = 1; i < n; ++i) ans = ans * i % mod;
21     printf("%lld\n", ans);
22 }
View Code

 

posted on 2018-08-21 08:25  cychester  阅读(191)  评论(0编辑  收藏  举报

导航