CF1770E Koxia and Tree 题解
相当诈骗,然而赛时卡 D 没开。
题意有点长,懒得复述了。
- 枚举 对一定不行,根据期望线性性,应当对每条边算其计入答案的期望次数。
- 把树变成有根树,对于 ,如果 子树内共有 只蝴蝶,则这条边被经过 次。
- 考虑到每条边至多被蝴蝶经过一次,每个 至多变化一次。
- 于是考虑实时维护 的期望值。
- 处理到 时,设有蝴蝶从 的概率是 ,则 概率 ,另有 概率 。
- 考虑把 求出来。 成立需要 处无蝴蝶、 处有蝴蝶、边定向为 。
- 实时维护 表示 点有蝴蝶的概率,则 。
- 当处理 时,。
- 据此可 维护 ,即 维护 ,即 处理每条边对答案的贡献。所以做完了,复杂度 。
#include <cstdio>
#include <iostream>
#include <algorithm>
#define LL long long
using namespace std;
const int M = 3e5 + 5, mod = 998244353;
int qpow(int a, int b){
long long ans = 1ll;
for(; b; b >>= 1) {if(b & 1) ans = 1ll * ans * a % mod; a = 1ll * a * a % mod;}
return ans;
}
int inv(int k) {return qpow(k, mod - 2);}
int add(int a, int b) {a += b; return a >= mod ? a-mod : a;}
int del(int a, int b) {a -= b; return a < 0 ? a+mod : a;}
void addn(int &x, int y) {x += y; if(x >= mod) x -= mod;}
void deln(int &x, int y) {x -= y; if(x < 0) x += mod;}
int fact(int x) {int ans = 1; for(int i = 1; i <= x; i++) ans = 1ll * ans * i % mod; return ans;}
void approx(int p, int q, int A) {
int x = q, y = p, a = 1, b = 0;
while (x > A) {
swap(x, y); swap(a, b);
a -= x / y * b;
x %= y;
}
printf("%d/%d\n", x, a);
}
struct edge {
int to, nxt;
} e[M << 1];
int head[M], cnt1;
void link(int u, int v){
e[++cnt1] = {v, head[u]}; head[u] = cnt1;
}
int n, m, p[M], pu[M], pv[M], s[M], dep[M], ans;
void dfs(int u, int fa) {
s[u] = p[u]; dep[u] = dep[fa] + 1;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to; if(v == fa) continue;
dfs(v, u);
addn(s[u], s[v]);
}
addn(ans, (1ll * s[u] * (m - s[u]) % mod + mod) % mod);
}
int main() {
scanf("%d %d", &n, &m);
for(int i = 1; i <= m; i++) {
int t; scanf("%d", &t);
p[t] = 1;
}
for(int i = 1; i <= n-1; i++) {
scanf("%d %d", &pu[i], &pv[i]);
link(pu[i], pv[i]); link(pv[i], pu[i]);
}
dfs(1, 0); // printf("ans=%d\n", ans);
// approx(mod, ans, 10);
#define u pu[i]
#define v pv[i]
const int inv2 = inv(2);
for(int i = 1; i <= n-1; i++) {
if(dep[u] > dep[v]) swap(u, v);
LL puv = 1ll * p[u] * (1 + mod - p[v]) % mod,
pvu = 1ll * p[v] * (1 + mod - p[u]) % mod;
LL tmp = 0;
tmp -= 1ll * puv * s[v] % mod * (m - s[v]) % mod;
tmp += 1ll * puv * (s[v]+1) % mod * (m - s[v] - 1) % mod;
tmp -= 1ll * pvu * s[v] % mod * (m - s[v]) % mod;
tmp += 1ll * pvu * (s[v]-1) % mod * (m - s[v] + 1) % mod;
tmp += mod; tmp %= mod;
p[u] = p[v] = 1ll * add(p[u], p[v]) * inv2 % mod;
addn(ans, 1ll * tmp * inv2 % mod);
ans += mod; ans %= mod;
// printf("ans=%d\n", ans);
// approx(mod, ans, 10);
}
printf("%d\n", 1ll * ans * inv(1ll * m * (m-1) / 2 % mod) % mod);
}
作者:purplevine
出处:https://www.cnblogs.com/purplevine/p/17018086.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
本文来自博客园,作者:purplevine,转载请注明原文链接:https://www.cnblogs.com/purplevine/p/17018086.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端