【题解】 ARC230A Meeting on Tree

题面


思路

首先这个东西直接做非常不可做啊,然后我们试着去刻画每条边经过了多少次,我们发现一条边经过的次数一定是左右两边被选的点数量的 \(\min\)

然后我们写一写式子:

\[\sum_{x=1}^n \sum_{a, b} C_{s_x}^{a} C_{n - s_x}^{b} \min(a, b) \]

其中 \(s_x\) 为任选某点作为根时 \(x\) 的子树大小。

然后我们有 \(2\min(a, b) = a + b - |a - b|\),然后继续推一下:

\[\sum_{x=1}^n \sum_{a, b} C_{s_x}^{a} C_{n - s_x}^{b} (a+b) \]

\[\sum_{x=1}^n \sum_{d = a + b} d \sum_a C_{s_x}^{a} C_{n - s_x}^{d - a} \]

然后我们发现这个是 范德蒙德卷积 的形式,然后转换之后有:

\[\sum_{x=1}^n \sum_{d} d C_{n}^{d} \]

然后我们有 吸收恒等式:

\[\sum_{x=1}^n n \sum_{d} C_{n - 1}^{d - 1} = \sum_{x=1}^n 2^{n - 1} n \]

然后我们试着化简另一部分:

\[\sum_{x=1}^n \sum_{a, b} C_{s_x}^{a} C_{n - s_x}^{b} |a - b| \]

\[\sum_{x=1}^n \sum_{d = |a - b|} d \sum_a (C_{s_x}^{a} C_{n - s_x}^{a + d} + C_{s_x}^{a+d} C_{n - s_x}^{a}) \]

\[\sum_{x=1}^n \sum_{d} d \sum_a (C_{s_x}^{a} C_{n - s_x}^{n - s_x - a - d} + C_{s_x}^{a+d} C_{n - s_x}^{n - s_x - a}) \]

\[\sum_{x=1}^n \sum_{d} d (C_{n}^{n - s_x - d} + C_{n}^{n - s_x + d})) \]

\[\sum_{x=1}^n \sum_{d} (d + s_x) C_{n}^{s_x + d} - s_x C_{n}^{s_x + d} + (d + n - s_x) C_{n}^{n - s_x + d} - (n - s_x) C_{n}^{n - s_x + d} \]

\[\sum_{x=1}^n n (\sum_{d} C_{n - 1}^{s_x - 1 + d} + C_{n - 1}^{n - s_x + d - 1}) - s_x (\sum_d C_{n}^{s_x + d}) -(n - s_x) (\sum_d C_{n}^{n - s_x + d}) \]

然后预处理 \(C_{n}^i\)\(C_{n - 1}^i\) 的后缀和就可以了。

代码

```cpp
//奇跡を信じて,願いを叶えて
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
#define uint unsigned long long
#define Air
namespace io{
	inline int read(){
		int f = 1, t = 0; char ch = getchar();
		while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();}
		while(ch >= '0' && ch <= '9'){t = t * 10 + ch - '0'; ch = getchar();}
		return t * f;
	}
	inline void write(int x){
		if(x < 0){putchar('-'); x = -x;}
		if(x >= 10){write(x / 10);}
		putchar(x % 10 + '0');
	}
}
using namespace io;
int n;
const int N = 3e5 + 10, MOD = 998244353;
int fac[N], inv[N];
vector<int> e[N];
int quick_pow(int a, int b){
	if(!b) return 1;
	if(b & 1){
		return a * quick_pow(a, b - 1) % MOD;
	}
	else{
		int tmp = quick_pow(a, b / 2);
		return tmp * tmp % MOD;
	}
}
int siz[N];
void dfs(int now, int ff){
	siz[now] = 1;
	for(auto y: e[now]){
		if(y == ff) continue;
		dfs(y, now);
		siz[now] += siz[y];
	}
}
int C[2][N];
int Calc(int n, int m){
	if(m > n) return 0; 
	return fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}
signed main() {
#ifndef Air
	freopen(".in","r",stdin);
	freopen(".out","w",stdout);
#endif
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	n = read();
	fac[0] = inv[0] = 1;
	for(int i = 1; i < N; i++){
		fac[i] = fac[i - 1] * i % MOD;
		inv[i] = quick_pow(fac[i], MOD - 2);
	}
	int pw = 1;
	for(int i = 1; i < n; i++){
		int x = read(), y = read();
		e[x].push_back(y);
		e[y].push_back(x);
		pw *= 2; pw %= MOD;
	}
	for(int i = 0; i < n; i++){
		C[0][i] = Calc(n - 1, i);
	}
	for(int i = 0; i <= n; i++){
		C[1][i] = Calc(n, i);
	}
	for(int i = n; i >= 0; i--){
		C[0][i] += C[0][i + 1]; C[0][i] %= MOD;
		C[1][i] += C[1][i + 1]; C[1][i] %= MOD;
	}
	dfs(1, 0);
	int ans = 0;
	for(int i = 2; i <= n; i++){
		int val = n * pw % MOD;

		val += siz[i] * C[1][siz[i]] % MOD;
		val %= MOD;
		val += MOD - n * C[0][siz[i] - 1] % MOD;
		val %= MOD;
		
		val += (n - siz[i]) * C[1][n - siz[i]] % MOD;
		val %= MOD;
		val += MOD - n * C[0][n - siz[i] - 1] % MOD;
		val %= MOD;	

		val %= MOD;
		ans += val;
		ans %= MOD;

	}
	ans *= quick_pow(2, MOD - 2);
	ans %= MOD;
	cout << ans << '\n';
	return 0;
}
posted @ 2026-09-22 20:42  Air2011  阅读(7)  评论(0)    收藏  举报