【题解】 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;
}

浙公网安备 33010602011771号