题目链接:https://vjudge.net/contest/349653#problem/A
题目:给出n个点,n-1条边,构成一个树,要求求出多少个不相交的圆上的树。
思路:
一开始想计算所有的不合法的树上圆的个数num,然后n!- num,后来发现求不出来num。
正解:直接求合法的圆的个数。因为是一棵树,我们先考虑一个层数为2的子树的情况。
,可以将这棵子树上除跟节点外的所有节点进行全排列,然后放置跟节点(跟节点无论放在哪里都是合法的,不会产生任何交点,就像题目中的样例2),这些节点占用圆上一段连续的区间,所以我们相当于将一颗子树放到了圆上的一段弧上。然后我们递归考虑,跟节点为一个层数为2的树,它的每个节点都是一个子树,跟节点占用整个圆,然后每棵子树占用一段弧形。
我们设每棵子树上的方案数为f[i],每个节点的直接与他相连的节点数量为num[i](其实就是这个节点的度数),产生的方案数num[i]!,因为在这段连续的区间上可以随机排列。
所以,f[i] = ∏ num[i] (1<=i<=n)。然后可以旋转这棵树,已1~n不同的节点为跟节点,求出的最终结果就是n*f[i]。
参考文章一:https://www.cnblogs.com/dsrdsr/p/10994125.html
参考文章二:https://www.cnblogs.com/violet-acmer/p/10991346.html
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
typedef long long ll;
const ll mod = 998244353;
ll du[N] = {0},fac[N];
int main(void)
{
int n;
scanf("%d",&n);
fac[1] = 1ll;
for(int i=2;i<=n;i++)
{
int x,y;scanf("%d%d",&x,&y);
du[x]++;du[y]++;
fac[i] = fac[i-1]*i%mod;
}
ll ans = 1ll*n%mod;
for(int i=1;i<=n;i++)
{
ans = ans*fac[ du[i] ]%mod;
}
ans = (ans%mod + mod)%mod;
printf("%lld\n",ans);
return 0;
}