BZOJ1430 小猴打架 < Prufer序列+组合数学 >

Problem

小猴打架

Time  Limit:  5  Sec\mathrm{Time\;Limit:\;5\;Sec}
Memory  Limit:  162  MB\mathrm{Memory\;Limit:\;162\;MB}

Description

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

Input

一个整数NN,N≤106N\le10^6

Output

一行,方案数mod  9999991\mod{9999991}。

Sample Input

1
4

Sample Output

1
96

标签:Prufer序列 组合数学

Solution

由Prufer序列\mathrm{Prufer}序列可知,一棵有nn个点的树与一个长为n−2n-2的序列一一对应。那么确定出这样的序列的方案数即可确定最后形成的树的形态。易知这样的序列共有nn−2n^{n-2}个。再考虑构建树的顺序,即为n−1n-1个元素的全排列数,总数为(n−1)!(n-1)!。故答案为 nn−2−(n−1)!mod  9999991n^{n-2}-(n-1)!\mod{9999991}。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <bits/stdc++.h>
#define MOD 9999991
using namespace std;
typedef long long lnt;
template <class T> inline void read(T &x) {
x = 0; int c = getchar(), f = 1;
for (; !isdigit(c); c = getchar()) if (c == 45) f = -1;
for (; isdigit(c); c = getchar()) (x *= 10) += f*(c-'0');
}
int n; lnt ans = 1;
int main() {
read(n);
for (int i = 1; i <= n-2; i++) (ans *= 1LL*n) %= MOD;
for (int i = 1; i <= n-1; i++) (ans *= 1LL*i) %= MOD;
return printf("%lld\n", ans), 0;
}