当前位置: 首页 > news >正文

CSP-S 29

10.11

t3

赛后才看懂题面 \(\ldots\)

妈妈我会推式子!(骗你的其实我不会)

推完式子就过了。

考虑先求出 \(1\) 为根时的答案,之后换根即可。

开始拆贡献ing

对于根结点,由于一开始就是黑色所以一直有贡献,即 \((n-1)\times (n-1)!\)

这个应该挺显然的就不解释了。

之后考虑对于非根结点如何计算贡献。

观察到对于一个点,只要该结点子树内有结点被染过色,则该结点一直产生贡献。

于是对于每个非根结点,我们找到它子树内有结点第一次被染色,该结点加入整棵树的位置,即可统计该结点产生的贡献。

(这个位置我总感觉表述不清,具体的,对于一棵五个结点的树,有五个位置,令其根节点为 \(1\) (此时一号位置已固定),若 \(2\) 的子树内的结点第一次被染色是在三号位置,则 \(2\) 产生三次贡献(从三以后都产生贡献),不懂手模一下)

令当前结点为 \(u\) ,当前子树大小为 \(s_u\) .

贡献即为

$\sum_{i=1}^{n-s_u} \binom{s_u}{1} \times\binom{n-i-1}{s_u-1} \times(s_u-1)! \times (n-s_u-1)! \times(n-i) $

前两个是组合数,中间两个是阶乘,最后一个就是括号。

开始逐步解析:

首先看 \(\sum\) 上下界,\(i\) 枚举 \(u\) 子树内结点首次出现的位置,(此时我们将位置规定为 \(1\)\(n-1\),所以起始为 \(1\)),最晚出现位置就是剩余位置数等于 \(s_u\) ,故上界为 \(n-s_u\) ,将每个可能出现的位置产生贡献累加即为该结点的贡献.

第一个组合数表示从 \(s_u\) 个结点中选出 \(1\) 个放在该位置上。

第二个组合数表示将剩余的 \(s_u-1\) 个结点随意放到剩余的 \(n-i-1\) 个位置上。

第一个阶乘表示 \(s_u-1\) 个结点内部顺序可变,乘上其全排列。

第二个阶乘表示 \(n-s_u-1\) 个结点(即外部剩余结点)位置可变,乘上其全排列。

最后那部分就是贡献,该结点从次位置到最后一直产生贡献,故乘上 \(n-i\)(前面的组合数和阶乘处理的都是情况数).

然后盯着这坨式子 \(\ldots\)

化简吧!!!

省流:结果为 \(\frac{s_u}{s_u+1}\times n!\)

开始化简:

原式为:

$\sum_{i=1}^{n-s_u} \binom{s_u}{1} \times\binom{n-i-1}{s_u-1} \times(s_u-1)! \times (n-s_u-1)! \times(n-i) $

$\sum_{i=1}^{n-s_u} s_u!\times\binom{n-i-1}{s_u-1} \times (n-s_u-1)! \times(n-i) $

$s_u!(n-s_u-1)! \sum_{i=1}^{n-s_u} \binom{n-i-1}{s_u-1} \times(n-i) $

\(s_u!(n-s_u-1)! \sum_{i=1}^{n-s_u} \frac{(n-i)!}{(s_u-1)!(n-s_u-i)!}\)

\(s_u (n-s_u-1)! \sum_{i=1}^{n-s_u} \frac{(n-i)!}{(n-s_u-i)!}\)

那之后怎么办?

继续推!

需要用到结论:

$\sum_{k=s}^{n} \binom{k}{s} =\binom{n+1}{s+1} $

考虑换元,令 \(k=n-i\)

\(s_u (n-s_u-1)! \sum_{k=s}^{n-1} \frac{k!}{(k-s_u)!}\)

原来累加的 \(n-i\) 是从 \(n-s_u-1\)\(s_u\) ,现在是从 \(s_u\)\(n-s_u-1\) ,故等价。

$s_u (n-s_u-1)!s_u! \sum_{k=s}^{n-1} \binom{k}{k-s_u} $

\(s_u (n-s_u-1)!s_u!\binom{n}{s+1}\)

\(\frac{s_u (n-s_u-1)!s_u!n!}{(n-s_u-1)!(s_u+1)!}\)

\(\frac{s_u}{s_u+1}n!\)

推完了哈哈哈!

按照式子统计贡献,最后换根即可。

code

点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 10;
const int mod = 998244353;
int n, ans, Ans[N];
int siz[N], jc[N];
vector<int> e[N];inline int km(int a, int b)
{int ans = 1;while (b){if (b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;
}void dfs1(int x, int f)
{siz[x] = 1;for (auto y : e[x]){if (y == f)continue;dfs1(y, x);siz[x] += siz[y];}if (x != 1)ans = (ans + siz[x] * km(siz[x] + 1, mod - 2) % mod * jc[n] % mod) % mod;
}void dfs2(int x, int f)
{if (x != 1){int now = Ans[f];now = (now - siz[x] * km(siz[x] + 1, mod - 2) % mod * jc[n] % mod + mod) % mod;now = (now + (n - siz[x]) * km(n - siz[x] + 1, mod - 2) % mod * jc[n] % mod + mod) % mod;Ans[x] = now;}for (auto y : e[x]){if (y == f)continue;dfs2(y, x);}
}signed main()
{// freopen("black.in", "r", stdin);// freopen("black.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cin >> n;jc[0] = 1;for (int i = 1; i <= n + 1; ++i)jc[i] = jc[i - 1] * i % mod;for (int i = 1, u, v; i < n; ++i){cin >> u >> v;e[u].push_back(v);e[v].push_back(u);}ans = (ans + (n - 1) * jc[n - 1] % mod) % mod;// cerr << "ans=" << ans << "\n";dfs1(1, 0);Ans[1] = ans;dfs2(1, 0);for (int i = 1; i <= n; ++i)cout << Ans[i] << "\n";return 0;
}// s/(s+1)*f[n]
http://www.zskr.cn/news/25677.html

相关文章:

  • ES原理、zookeeper、kafka
  • LangGraph 记忆系统实战:反馈循环 + 动态 Prompt 让 AI 持续学习
  • 【HOWTO】购买和销售二手测试仪器指南
  • 小马算力致敬程序员
  • 蛋白表达标签:重组蛋白研究的精妙引擎
  • 106.腾讯地图位置服务再出错
  • Luogu P10034 「Cfz Round 3」Circle 题解 [ 蓝 ] [ 背包 DP ] [ 质数筛 ] [ 图论 ] [ 构造 ]
  • 20232410 2025-2026-1 《网络与系统攻防技术》实验二实验报告
  • SQLite简单使用
  • 心理咨询系统
  • Adaptive Learning Rate(自适应学习率) - -一叶知秋
  • 新学期每日总结(第12天)
  • 17 线程的创建
  • 2025.10.20总结 - A
  • 一般公共预算收入 + 全国政府性基金收入
  • 傻瓜式处理kauditd0病毒程序记录
  • 软件工程第二次团队作业
  • 好用的网址
  • 低代码赋能业务创新:打破数字鸿沟,释放业务潜能
  • 10/20/2025杂题 关于在线性时间内求解低次多项式的幂
  • 计算机毕业设计 基于EChants的海洋气象数据可视化平台设计与建立 Python 大数据毕业设计 Hadoop毕业设计选题【附源码+文档报告+安装调试】
  • ZR 2025 NOIP 二十连测 Day 5
  • 关于单片机内部ADC采样率,采样精度的理解与计算整理 - 实践
  • Mac版PDF Squeezer v4.5.1安装教程(DMG文件下载+详细步骤)​
  • 详细揭秘:马拉车算法
  • 黑马程序员Java基础笔记
  • 实用指南:linux磁盘空间爆满排查与清理
  • 详细介绍:从零开始的C++学习生活 2:类和对象(上)
  • 【aigc】chrome-devtools-mcp怎么玩? - 指南
  • 记账:流水报表