Live2D

Solution -「GLR-R2」教材运送

Description

  Link.

  给定一棵包含 n 个点,有点权和边权的树。设当前位置 s(初始时 s=1),每次在 n 个结点内随机选择目标结点 t,付出「st 的简单路径上的边权之和」×t 的点权」的代价,标记(可以重复标记)点 t 并把 s 置为 t。求每个点至少被标记一次时(其中 1 号结点一开始就被标记)代价之和的期望。答案对 998244353 取模。

  n106

Solution

  首先,有期望意义下的 Min-Max 容斥的公式:

E(max(S))=TST(1)|T|1E(min(T))

  对于本题,S={2,3,,n},要求的答案等价于标记最后一个未标记点时代价的期望,那么枚举上式中的 T,并设 |T|=m,我们只需要对于每个 T,求出从结点 1 出发,标记 T 集合内任意一个点的期望代价就行。

  考虑一个朴素的 DP:令 fT(u) 表示现在在 u 点(u 点已标记)时,标记 T 内任意一点的期望代价。显然:

fT(u)={0uT1n(v=1nfT(v)+dist(u,v))uT

  其中 dist(u,v) 即表示题意中把 u 置为 v 的代价。到此,你就可以获得 10 分的好成绩啦!


  接下来,取出一个 uTfT(u) 来研究:

fT(u)=1n(v=1nfT(v)+dist(u,v))nfT(u)v=1nfT(v)=v=1ndist(u,v)

  令 s=vTf(v)w(u)=v=1ndist(u,v)C=ST={c1,c2,,cnm}(其中恒有 c1=1)列出共 |C| 个等式:

nfT(c1)s=w(c1)nfT(c2)s=w(c2)nfT(cnm)s=w(cnm)}nm equations in total.

  左右分别相加得到:

ns(nm)s=vTw(v)s=vTw(v)m

  于是乎,要求的 fT(1) 就有:

fT(c1)=s+w(1)n


  此后,把 fT(1) 带入答案的式子里:

TST(1)|T|1fT(1)=TST(1)|T|1(w(1)n+uTw(u)n|T|)=1nm=1n1(1)m1[(n1m)w(1)+1mTS|T|=muTw(u)]

  令 g(m)=TS|T|=mvTw(v),单独考虑结点 1,它必然不属于 T;再考虑其他结点的贡献次数,可以得出:

g(m)=(n1m)w(1)+(n2m)u=2nw(u)

  最后,只需要求出 u=1nw(u)。分别考虑每条边 (u,v,b)E 的贡献。将这条边删去,记此时 u 所在联通块的结点个数为 pu,结点点权之和为 quv 同理。则:

u=1nw(u)=(u,v)Eb(u,v)(puqv+pvqu)

  综上,求出这一系列式子,问题就以 O(n) 的复杂度解决啦!

Code

/* Clearink */

#include <cstdio>

inline char fgc () {
	static char buf[1 << 17], *p = buf, *q = buf;
	return p == q && ( q = buf + fread ( p = buf, 1, 1 << 17, stdin ), p == q ) ? EOF : *p++;
}

inline int rint () {
	int x = 0; char s = fgc ();
	for ( ; s < '0' || '9' < s; s = fgc () );
	for ( ; '0' <= s && s <= '9'; s = fgc () ) x = x * 10 + ( s ^ '0' );
	return x;
}

const int MAXN = 1e6, MOD = 998244353;
int n, ecnt, head[MAXN + 5], val[MAXN + 5], fac[MAXN + 5], ifac[MAXN + 5];
int fa[MAXN + 5], siz[MAXN + 5], sum[MAXN + 5], dist[MAXN + 5]; // dist[i]==dist(1,i).
int g[MAXN + 5];

inline int mul ( const long long a, const int b ) { return a * b % MOD; }
inline int sub ( int a, const int b ) { return ( a -= b ) < 0 ? a + MOD : a; }
inline int add ( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
inline void addeq ( int& a, const int b ) { ( a += b ) >= MOD && ( a -= MOD, 0 ); }

struct Edge { int to, cst, nxt; } graph[MAXN * 2 + 5];

inline void link ( const int s, const int t, const int c ) {
	graph[++ecnt] = { t, c, head[s] };
	head[s] = ecnt;
}

inline int qkpow ( int a, int b ) {
	int ret = 1;
	for ( ; b; a = mul ( a, a ), b >>= 1 ) ret = mul ( ret, b & 1 ? a : 1 );
	return ret;
}

inline void init () {
	fac[0] = 1;
	for ( int i = 1; i <= n; ++i ) fac[i] = mul ( i, fac[i - 1] );
	ifac[n] = qkpow ( fac[n], MOD - 2 );
	for ( int i = n - 1; ~i; -- i ) ifac[i] = mul ( i + 1ll, ifac[i + 1] );
}

inline int inv ( const int x ) { return mul ( fac[x - 1], ifac[x] ); }

inline int comb ( const int n, const int m ) {
	return n < m ? 0 : mul ( fac[n], mul ( ifac[m], ifac[n - m] ) );
}

inline void dfs ( const int u ) {
	siz[u] = 1, sum[u] = val[u];
	for ( int i = head[u], v; i; i = graph[i].nxt ) {
		if ( ( v = graph[i].to ) ^ fa[u] ) {
			dist[v] = add ( dist[fa[v] = u], graph[i].cst );
			dfs ( v ), siz[u] += siz[v], addeq ( sum[u], sum[v] );
		}
	}
}

int main () {
	n = rint ();
	int vs = 0;
	for ( int i = 1; i <= n; ++i ) vs = add ( vs, val[i] = rint () );
	for ( int i = 1, u, v, w; i < n; ++i ) {
		u = rint (), v = rint (), w = rint ();
		link ( u, v, w ), link ( v, u, w );
	}
	init (), dfs ( 1 );
	int S = 0;
	for ( int u = 1; u <= n; ++u ) {
		for ( int i = head[u], v; i; i = graph[i].nxt ) {
			if ( ( v = graph[i].to ) ^ fa[u] ) {
				addeq ( S, mul ( graph[i].cst,
					add ( mul ( siz[v], sub ( vs, sum[v] ) ),
						mul ( n - siz[v], sum[v] ) ) ) );
			}
		}
	}
	for ( int i = 2; i <= n; ++i ) addeq ( g[n - 1], mul ( val[i], dist[i] ) );
	for ( int i = n - 2; i; --i ) {
		g[i] = add ( mul ( comb ( n - 1, i ), g[n - 1] ),
			mul ( comb ( n - 2, i ), sub ( S, g[n - 1] ) ) );
	}
	int ans = 0;
	for ( int i = 1; i < n; ++i ) {
		ans = ( i & 1 ? add : sub )( ans,
			add ( mul ( comb ( n - 1, i ), g[n - 1] ), mul ( inv ( i ), g[i] ) ) );
	}
	printf ( "%d\n", mul ( ans, inv ( n ) ) );
	return 0;
}
posted @   Rainybunny  阅读(147)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示