[题解] AT_abc386_g [ABC386G] Many MST

posted on 2024-12-30 11:11:16 | under | source

题意:为完全图的每条边赋值 \([1,m]\),求所有情况下 MST 权值之和。

不妨认为权值为 \([0,m)\),最后再加回去即可。

无从下手,需要做一步转化:考虑 kruskal 的过程,依次将权值为 \(0\dots m-1\) 的边加入。不妨记 \(G_k\) 为将 \(<k\) 的边全部加入后得到的图,\(c(G_k)\)\(G_k\) 的连通分量集合。那么 \(n-|c(G_k)|\) 等于 MST 上权值 \(< k\) 的边数量,所以有:

\[\sum\limits_{e\in MST} w=\sum\limits_{e\in MST}m-1-\sum\limits_{i=1}^{m-1}[w<i] =\sum\limits_{k=1}^{m} |c(G_k)|-m \]

对于 \(-m\),总的贡献是 \(-m^{\frac {n(n-1)}2+1}\)。而 \(|c(G_k)|\) 等价于求满足条件的连通分量数量,枚举 \(k\),枚举连通分量 \(T\),记 \(V,E\)\(T\) 的点数和边数,那么使它在 \(k\) 时产生贡献的赋值方案数为:

\[k^{E}m^{\frac {(n-V)(n-V-1)}2}(m-k)^{\frac {V(V-1)}2-E}(m-k)^{V(n-V)} \]

含义是:内部边 \(< k\),外部边随意,对于连接内外部或在内部但不在连通分量内的边,取值 \(\ge k\)

不妨枚举 \(V=s\),那么 \(k\) 的总贡献就是:

\[\sum\limits_{s=1}^{n}\sum\limits_{|T|=s} k^{E}m^{\frac {(n-s)(n-s-1)}2}(m-k)^{\frac {s(s-1)}2-E}(m-k)^{s(n-s)} \]

提取公因式:

\[\sum\limits_{s=1}^{n}m^{\frac {(n-s)(n-s-1)}2}(m-k)^{s(n-s)}\sum\limits_{|T|=s} k^{E}(m-k)^{\frac {s(s-1)}2-E} \]

并不关心点的编号,所以记 \(f(s)\) 为连通分量大小为 \(s\) 时,后面那串式子的值,代入:

\[\sum\limits_{s=1}^{n}m^{\frac {(n-s)(n-s-1)}2}(m-k)^{s(n-s)}{{n}\choose{s}}f(s) \]

求出 \(f\) 即可。对于连通分量一类的计数问题,可以借鉴 ABC213G 的做法,即总价值减去不连通情况的价值。先看看总价值 \(W\)

\[W=\sum\limits_{E=0}^{\frac {s(s-1)}2} k^E(m-k)^{\frac {s(s-1)}2 -E}=(m-k)^{\frac {s(s-1)}2}(1+\frac {k}{m-k})^{\frac {s(s-1)}2}=m^{\frac {s(s-1)}2} \]

然后是不连通的价值 \(W_2\)。不连通可以看做:\(1\) 所在连通分量、其它点随意组合(这个刚刚解决了)。单独计算两部分的价值都是容易的,将其乘起来后,发现只需修正 \((m-k)^{\frac{s(s-1)}2}\) 这部分即可:

\[W_2=\sum\limits_{i=1}^{s-1} {{s-1}\choose {i-1}}f_im^{\frac{(s-i)(s-i-1)}2}(m-k)^{i(s-i)} \]

最后 \(f_s=W-W_2\)

完结撒花,复杂度 \(O(n^2m)\)

代码

注意常数优化。

#include<bits/stdc++.h>
#pragma GCC optimize(3, "Ofast", "inline")
using namespace std;

#define ADD(a, b) a = (a + b) % mod
const int N = 5e2 + 5, mod = 998244353;
int n, m, ans, f[N], jc[N], jcinv[N];
int qstp[N][N * N], C[N][N];

inline void solve(int k){
	for(int s = 1; s <= n; ++s){
		f[s] = qstp[m][s * (s - 1) / 2];
		for(int i = 1; i < s; ++i)
			ADD(f[s], 1ll * (mod - 1) * f[i] % mod * C[s - 1][i - 1] % mod * qstp[m][(s - i) * (s - i - 1) / 2] % mod * qstp[m - k][i * (s - i)] % mod);
		ans = (ans + 1ll * qstp[m][(n - s) * (n - s - 1) / 2] * qstp[m - k][s * (n - s)] % mod * C[n][s] % mod * f[s] % mod) % mod;
	}
}
signed main(){
	for(int i = 0; i < N; ++i){
		qstp[i][0] = 1, C[i][0] = C[i][i] = 1;
		for(int j = 1; j < N * N; ++j) qstp[i][j] = 1ll * qstp[i][j - 1] * i % mod; 
		for(int j = 1; j < i; ++j) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
	}
	cin >> n >> m;
	ans = (1ll * (n - 1) * qstp[m][n * (n - 1) / 2] % mod + 1ll * (mod - 1) * qstp[m][n * (n - 1) / 2 + 1] % mod) % mod;
	for(int i = 1; i <= m; ++i) solve(i);
	cout << ans; 
	return 0;
}
posted @ 2026-01-13 11:21  Zwi  阅读(0)  评论(0)    收藏  举报