【题解】CF1770E Koxia and Tree
题目(cf)
题目(洛谷)
题目大意
给定 n n n 个节点的无根树,有 k k k 个指定的节点上有蝴蝶。对每条边等概率地指定任意方向,按照边的编号顺序查找每条边,若边 u → v u\to v u→v 满足 u u u 有蝴蝶且 v v v 没有蝴蝶,则蝴蝶从 u u u 飞到 v v v. 求两只蝴蝶之间距离的期望值。
题解
首先要注意,求期望值的两只蝴蝶不是给定的。
显然,这个期望值的求法是每条边的贡献累加,求出所有蝴蝶两两距离和的期望值,再除以选择两只蝴蝶的方案数 C k 2 = k ( k − 1 ) 2 C_k^2=\frac {k(k-1)}{2} Ck2=2k(k−1).
先考虑一个简化的经典问题:蝴蝶不会飞的情况。
枚举每条边,若其左边有 x x x 只蝴蝶,那么其右边有 k − x k-x k−x 只蝴蝶,这条边将会成为 x × ( k − x ) x\times (k-x) x×(k−x) 对蝴蝶之间的路径上的一条边。换一种说法,有 x × ( k − x ) x\times (k-x) x×(k−x) 条路径会经过这条边。那么这条边会对总距离值贡献 x × ( k − x ) x\times (k-x) x×(k−x). 也就是说简化情况下 a n s = ∑ ( u , v ) ∈ M s u m u ( k − s u m u ) k ( k − 1 ) 2 ans=\frac{\sum\limits_{(u,v)\in M}sum_u(k-sum_u)}{\frac{k(k-1)}{2}} ans=2k(k−1)(u,v)∈M∑sumu(k−sumu). s u m i sum_i sumi 表示 i i i 的子树中有多少只蝴蝶。这个可以一次dfs O ( n ) O(n) O(n) 求出。
回到原问题。如果我们知道每条边两边分别有多少蝴蝶,则贡献可求。
思考发现对于边 ( u , v ) (u,v) (u,v),不管蝴蝶怎么飞, s u m sum sum 值的变化量最大为 1 1 1. 而 s u m sum sum 是否改变只取决于 u u u 和 v v v 上是否有蝴蝶。这就是说,我们需要求出 u u u 和 v v v 有蝴蝶的概率。设这个概率为 p p p.
考虑对于 p u p_u pu:
- 原来 u u u 和 v v v 上都有蝴蝶,则现在 u u u 有蝴蝶的概率为 p u × p v p_u\times p_v pu×pv.
- 原来 u u u 和 v v v 上都没有蝴蝶,则现在 u u u 有蝴蝶的概率为 0 0 0.
- 原来 u u u 有蝴蝶, v v v 没有,则现在 u u u 有蝴蝶的概率为 p u ( 1 − p v ) 2 \frac {p_u(1-p_v)}{2} 2pu(1−pv). 因为有 1 2 \frac 1 2 21 的概率边 ( u , v ) (u,v) (u,v) 变成 v → u v\to u v→u,只有这样蝴蝶才不会从 u u u 飞到 v v v.
- 原来 u u u 没有蝴蝶, v v v 有,则现在 u u u 有蝴蝶的概率为 ( 1 − p u ) p v 2 \frac {(1-p_u)p_v}{2} 2(1−pu)pv. 因为有 1 2 \frac 1 2 21 的概率边 ( u , v ) (u,v) (u,v) 变成 v → u v\to u v→u,只有这样蝴蝶才会从 v v v 飞到 u u u.
对上述概率求和,得到 u u u 有蝴蝶的概率为 p u p v + p u ( 1 − p v ) 2 + ( 1 − p u ) p v 2 = p u + p v 2 p_up_v+\frac {p_u(1-p_v)}{2}+\frac {(1-p_u)p_v}{2}=\frac {p_u+p_v}{2} pupv+2pu(1−pv)+2(1−pu)pv=2pu+pv.
也就是转移时 p u = p u + p v 2 p_u=\frac {p_u+p_v}{2} pu=2pu+pv. 对于 p v p_v pv 同理,得 p u = p v = p u + p v 2 p_u=p_v=\frac {p_u+p_v}{2} pu=pv=2pu+pv.
在修改概率前,我们就需要对边 ( u , v ) (u,v) (u,v) 统计答案。
考虑如下情况:
- u u u 和 v v v 都有蝴蝶,贡献为 p u ⋅ p v ⋅ s u m u ⋅ ( k − s u m u ) p_u\cdot p_v\cdot sum_u\cdot (k-sum_u) pu⋅pv⋅sumu⋅(k−sumu)
- u u u 和 v v v 都没蝴蝶,贡献为 ( 1 − p u ) ⋅ ( 1 − p v ) ⋅ s u m u ⋅ ( k − s u m u ) (1-p_u)\cdot (1-p_v)\cdot sum_u\cdot (k-sum_u) (1−pu)⋅(1−pv)⋅sumu⋅(k−sumu)
- u u u 有蝴蝶, v v v 没有蝴蝶,此时有 1 2 \frac 1 2 21 的概率蝴蝶从 u u u 飞到 v v v,导致 s u m u sum_u sumu 少 1 1 1,贡献为 p u ⋅ ( 1 − p v ) ⋅ s u m u ⋅ ( k − s u m u ) + ( s u m u − 1 ) ( k − s u m u + 1 ) 2 p_u\cdot (1-p_v)\cdot \frac {sum_u\cdot (k-sum_u)+(sum_u-1)(k-sum_u+1)}{2} pu⋅(1−pv)⋅2sumu⋅(k−sumu)+(sumu−1)(k−sumu+1)
- u u u 没有蝴蝶, v v v 有蝴蝶,此时有 1 2 \frac 1 2 21 的概率蝴蝶从 v v v 飞到 u u u,导致 s u m u sum_u sumu 多 1 1 1,贡献为 ( 1 − p u ) ⋅ p v ⋅ s u m u ⋅ ( k − s u m u ) + ( s u m u + 1 ) ( k − s u m u − 1 ) 2 (1-p_u)\cdot p_v\cdot \frac {sum_u\cdot (k-sum_u)+(sum_u+1)(k-sum_u-1)}{2} (1−pu)⋅pv⋅2sumu⋅(k−sumu)+(sumu+1)(k−sumu−1)
对以上 4 4 4 种情况求和就是边 ( u , v ) (u,v) (u,v) 的贡献。
具体实现的时候可以对 u u u 和 v v v 限定父子关系,这样容易计算。
记得最后要除以 k ( k − 1 ) 2 \frac {k(k-1)}{2} 2k(k−1).
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 300005;
const LL mod = 998244353;
int n, k, cnt = 0, fir[N], nxt[N << 1], to[N << 1], fa[N];
LL ans = 0, p[N], s[N];
void ade(int u, int v) {cnt++, nxt[cnt] = fir[u], fir[u] = cnt, to[cnt] = v;cnt++, nxt[cnt] = fir[v], fir[v] = cnt, to[cnt] = u;
}
LL qpow(LL x, LL y) {LL sum = 1;while (y) {if (y & 1) sum = sum * x % mod;x = x * x % mod, y >>= 1;}return sum;
}
void dfs(int r, int f) {fa[r] = f, s[r] = p[r];for (int i = fir[r]; i; i = nxt[i])if (to[i] != f)dfs(to[i], r), s[r] += s[to[i]];
}
int main() {scanf("%d%d", &n, &k);for (int i = 1, x; i <= k; i++) scanf("%d", &x), p[x] = 1;for (int i = 1, u, v; i < n; i++) scanf("%d%d", &u, &v), ade(u, v);dfs(1, 0);LL inv2 = qpow(2, mod - 2);for (int i = 1; i <= cnt; i += 2) {int u = to[i], v = to[i + 1];if (fa[v] != u) swap(u, v);//限定 u 为 v 的父亲ans = ((ans+ p[u] * p[v] % mod * s[v] % mod * (k - s[v]) % mod+ (1 - p[u]) * (1 - p[v]) % mod * s[v] % mod * (k - s[v]) % mod+ (1 - p[u]) * p[v] % mod * (s[v] * (k - s[v]) % mod + (s[v] - 1) * (k - s[v] + 1) % mod) % mod * inv2 % mod+ p[u] * (1 - p[v]) % mod * (s[v] * (k - s[v]) % mod + (s[v] + 1) * (k - s[v] - 1) % mod) % mod * inv2 % mod) % mod + mod) % mod;p[u] = p[v] = (p[u] + p[v]) * inv2 % mod;//概率转移}printf("%lld", (ans * qpow(1ll * k * (k - 1) / 2 % mod, mod - 2) % mod + mod) % mod);return 0;
}
END
【题解】CF1770E Koxia and Tree相关推荐
- CF1770E Koxia and Tree
题目描述 Imi has an undirected tree with n n n vertices where edges are numbered from 1 1 1 to n − 1 n-1 ...
- LeetCode题解:Balanced Binary Tree
Given a binary tree, determine if it is height-balanced. For this problem, a height-balanced binary ...
- 题解-hzy loves segment tree I
Problem 题目概要:给定一棵 \(n\) 个节点的树,点有点权,进行 \(m\) 次路径取\(\max\)的操作,最后统一输出点权 \(n\leq 10^5,m\leq 5\times 10^6 ...
- 阔力梯的树(2020 CCPC Wannafly Winter Camp Day2 Div.12 )dsu on tree
题解: dsu on tree dsu on tree的基本步骤就不说了 看到这题询问结点的子树问题,而且询问时离线的,首先想到的dsu on tree的这个trick. 本题的难题就是如何维护结点所 ...
- CF570D Tree Requests(dsu on tree)
题解: dsu on tree 首先dsu on tree是一个离线的算法,所以我们需要先把他们的询问储存起来,然后进行操作. 针对于每一个结点,我们先统计出他和他子树的所有信息,然后对于这个结点来说 ...
- dsu on tree 模板题目(CF600E Lomsat gelral)
题解: dsu on tree 对于结点i来说,步骤为: 递归轻儿子,不保留贡献. 递归重儿子,保留贡献. 统计当前结点及所有轻儿子的贡献. 拿个样例来解释算法的流程 比如说样例2: 如图所示,有多个 ...
- LeetCode 145. Binary Tree Postorder Traversal
原题链接在这里:https://leetcode.com/problems/binary-tree-postorder-traversal/ 题目: Given a binary tree, retu ...
- 由任意二叉树的前序遍历序列和中序遍历序列求二叉树的思想方法_算法与数据结构基础 - 二叉树(Binary Tree)...
二叉树基础 满足这样性质的树称为二叉树:空树或节点最多有两个子树,称为左子树.右子树, 左右子树节点同样最多有两个子树. 二叉树是递归定义的,因而常用递归/DFS的思想处理二叉树相关问题,例如Leet ...
- 2019年12月7日PAT甲级满分题解与经验总结
PAT2019冬季甲级满分代码+占坑经验分享 考题体验 A题 题目+题解 题目 题解 B题 题目+题解 题目 题解 C题 题目+题解 题目 题解 D题 题目+题解 题目 题解 考场体验,ide经验提高 ...
最新文章
- 有 OC 经验的程序员快速学习 Swift 语法
- PHP的ob输出缓冲函数作用
- 在同一个类中调用另一个方法没有触发 Spring AOP 的问题
- MySQL史上最快逻辑备份工具
- 【Kettle】job中设置自动发送邮件
- web自动化测试第6步:模拟鼠标操作(ActionChains)
- android 通过platform.pk8,platform.x509.pem生成jks签名文件
- 【安卓】悬浮球源代码(长按判断、多次点击判断、自动贴边)
- 有什么软件可以测试游戏视频数据,免费录制游戏视频软件有哪些?看完你就知道了...
- VS code 使用技巧-设置鼠标滚轮翻页速度(Mac版本)
- 惠普f5静音键指示灯不亮(转载)
- 江民KV2007离线包和安装包下载
- 点云配准--4PCS原理与应用
- 对封装、继承、多态、抽象的理解
- 如何把一个qmake的Ubuntu手机应用打包为一个snap应用
- [转载] 蝴蝶上如何做种候选及发布
- 想知道车牌号码里都有什么秘密吗?
- 小米机器人扫地机贴纸_这次小米没吹牛,小米机器人扫地机评测
- Python数据采集与处理之网页爬取
- “编程思维”到底是一种什么样的思维?