Codeforces Round #564 (Div. 2) D(组合数学/树上DP)

D. Nauuo and Circle

题意:
  给定一棵n个节点的树,从1n编号,现在你需要玩弄这棵树。问按照顺时针遍历能获得多少种不同的序列。最后的答案对%998244353
思路:
  定义son[u]表示u的子节点的个数。先固定1是这个序列中的第一个,因为这是一个环所以最后的答案要乘上n。定义dp[u]表示的是以u为节点的方案数。
  对于节点1,我们可以就是对son[u]进行全排列,并将排列方式放在1的后面,将son[u]全排列一共有Ason[u]son[u]种方案,也就是son[u]!种方案,而它的每一个儿子v同样也有它们的子节点,所以就得到了式子dp[u]=son[u]!vG[u]dp[v]
而对于非1节点,它们自身也可以进行全排列所以对于非1的节点,它们的方案数的表达式是dp[u]=(son[u]+1)!vG[u]dp[v]
所以最后我们将两种情况合并就是dp[u]=du[u]!vG[u]dp[v]其中du[u]表示的是du[u]的度

void solve() { int n; std::cin >> n; fac[0] = 1; rep(i,1,N) fac[i] = fac[i - 1] * i; std::vector<int> G[n + 1], du(n + 1); rep(i,0,n - 1) { int u, v; std::cin >> u >> v; G[u].push_back(v), G[v].push_back(u); du[v] ++, du[u] ++; } std::vector<Z> dp(n + 1); std::function<void(int, int)> dfs = [&] (int u, int fa) -> void { Z res = 1; for (auto v : G[u]) { if (v == fa) continue; dfs(v, u); res = res * dp[v]; } dp[u] = fac[du[u]] * res; }; dfs(1, 0); Z ans = dp[1] * n; std::cout << ans.val() << "\n"; }

__EOF__

本文作者HoneyGrey
本文链接https://www.cnblogs.com/Haven-/p/16151690.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   浅渊  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示