题解 CF1762E 【Tree Sum】
注意到样例中除了答案为
接下来我们可以观察出下面的结论:
- Observation 1:当且仅当
n 为偶数时符合条件的树存在。
证明:若一棵
- Observation 2:当
n 为偶数且树的形态固定,满足条件的填边权方案唯一。
证明:像 Prufer 序列那样依次给叶子与其相连的边填数并删除叶子,可以得到唯一的填数方案。
- Observation 3:一条边
(u, v) 权值为1 当且仅当割断这条边后u 或v 所在连通块大小为偶数。
证明:连上前还是两边分别像上面那样填(但是把
现在我们来考虑怎么算。
显然可以逐边算贡献。枚举
- 边权为
(-1)^i 。 - 从剩下
n - 2 个点中选出i - 1 个点扔到1 那边、余下n - i - 1 个点扔到n 那边去,方案数为C_{n - 2}^{i - 1} 。 - 两边随便构造无根树,方案数为
f_i f_{n - i} ,其中f_n = n^{n - 2} 。 - 两边随便各选一个点连边,方案数为
i(n - i) 。
对每个
代码:
#include <stdio.h>
typedef long long ll;
const int mod = 998244353;
ll fac[500007], inv_fac[500007];
inline ll quick_pow(ll x, ll p, ll mod){
ll ans = 1;
while (p){
if (p & 1) ans = ans * x % mod;
x = x * x % mod;
p >>= 1;
}
return ans;
}
inline void init(int n){
fac[0] = 1;
for (register int i = 1; i <= n; i++){
fac[i] = fac[i - 1] * i % mod;
}
inv_fac[n] = quick_pow(fac[n], mod - 2, mod);
for (register int i = n - 1; i >= 0; i--){
inv_fac[i] = inv_fac[i + 1] * (i + 1) % mod;
}
}
inline ll comb(int n, int m){
if (n < 0 || m < 0 || n < m) return 0;
return fac[n] * inv_fac[m] % mod * inv_fac[n - m] % mod;
}
inline ll f(int n){
if (n == 1) return 1;
return quick_pow(n, n - 2, mod);
}
int main(){
int n;
scanf("%d", &n);
if (n % 2 == 1){
printf("0");
return 0;
}
ll ans = 0;
init(n);
for (register int i = 1; i < n; i++){
if (i % 2 == 0){
ans = (ans + (ll)i * (n - i) % mod * comb(n - 2, i - 1) % mod * f(i) % mod * f(n - i) % mod) % mod;
} else {
ans = ((ans - (ll)i * (n - i) % mod * comb(n - 2, i - 1) % mod * f(i) % mod * f(n - i) % mod) % mod + mod) % mod;
}
}
printf("%lld", ans);
return 0;
}