1430: 小猴打架
Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 644 Solved: 469
[Submit][Status][Discuss]
Description
一开始森林里面有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}六种不同的打架过程。
Input
一个整数N。
Output
一行,方案数mod 9999991。
Sample Input
4
Sample Output
96
HINT
50%的数据N<=10^3。
100%的数据N<=10^6。
prufer编码
任意两个猴子都可以打架,连边后发现是完全图
由Cayley公式可知,对于一个完全图
其生成树个数为n^(n-2)
又因为猴子打架的顺序不同,所以*(n-1)!
如果你不知道prufer编码的话呢
1. 一棵标号树的prufer编码规则如下
找到标号最小的叶子节点,输出与它相邻的节点到prufer序列
将该叶子节点删去,反复操作,直至剩余2个节点。
2. 由prufer编码生成树
任何一个prufer 序列可以唯一对应到一棵有标号的树
首先标记所有节点为未删除 依次扫描prufer 序列中的数
比如当前扫描到第k个数u,说明有一个叶子节点连到u,并在当前操作中被删除
找一个标号最小的未被标记为删除的且在prufer 序列第k个位置后未出现过的节点v,在u,v间连边并将v删除
反复操作,最后剩两个节点未被标记为删除,在它们之间连边,这样得到的一个图含有n-1条边则是一棵树
3. 生成树计数Cayley公式
一棵树N个结点,其prufer序列有N-2个位置因此可以在这N-2个位置里面任何的填充1~N之间的数形成一个prufer序列
且一个prufer序列唯一的对应一颗生成树
于是完全图的生成树的数目为N^(N-2)
#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<complex>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<bitset>
#include<string>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
const int mod=9999991;
int qpow(int a,int b)
{
int ans=1;
while(b)
{
if(b&1)ans=ll(ans)*a%mod;
a=ll(a)*a%mod;
b>>=1;
}
return ans;
}
int main()
{
int n=read();
int ans=qpow(n,n-2);
for(int i=2;i<n;i++)ans=ll(ans)*i%mod;
printf("%d\n",ans);
return 0;
}