题解:AT_abc386_g [ABC386G] Many MST

· · 题解

公式恐惧症慎入

题目要求边权在 1\sim M 之间,我们转化一下,变成 0\sim M-1 之间,最后再将答案加上 (N-1)\times M^{N(N-1)\over2} 就行了。

对于一个图 G,设 $G_k

为什么? 如果一条边权为 $v$ 边在最小生成树内,那么只有枚举的 $k$ 在 $v+1\sim M$ 的时候才会有这条边,换句话说,也就是才会让联通块数减一。 那么,在这之前,$k$ 从 $1\sim v$ 共 $v$ 次枚举时联通块数会多一,总共就正好加上了 $v$。 减一是因为最小生成树的点数比边数多 $1$。 原式又可化简为 $-M+\sum_{k=1}^{M} c(G_k)$。 设 $S$ 是所有 $M^{N(N+1)\over2}$ 个完全图的集合,$C(G_k)$ 是 $G_k$ 的连通块的集合,那么总答案为: $$ \begin{aligned} &(N-1)\times M^{N(N-1)\over2}+\sum_{G\in S}\left(-M+\sum_{k=1}^{M}c(G_k)\right)\\ =&(N-1)\times M^{N(N-1)\over2}-M\times M^{N(N-1)\over2}+\sum_{k=1}^{M}\sum_{G\in S}c(G_k)\\ =&(N-1-M)\times M^{N(N-1)\over2}+\sum_{k=1}^{M}\sum_{G\in S}\sum_{H\in C(G_k)}1 \end{aligned} $$ 到这里应该都挺好理解的。 下面,我们将推导如何为每个 $k$ 求出 $\sum_{G\in S}\sum_{H\in C(G_k)}1$。 对于一个 $H$,我们设它有 $V$ 个点与 $L$ 条边,那么有 $H\in C(G_k)$ 的图 $G\in S$ 的 $H$ 的数量有如下数量个。 $$ (M-k)^{{V(V-1)\over2}-L}\times k^L\times (M-k)^{V(N-V)}\times M^{(N-V)(N-V-1)\over2} $$ 我们考虑 $G$ 中每条边的情况来得出这个式子。 对于两个端点都在 $H$ 中的边,由于只能有 $L$ 条边显示出来,即有 $L$ 条边的权值为 $0\sim k-1$,共 $k$ 种取值,于是一共有 $k^L$ 种情况,剩下共 ${V(V-1)\over2}-L$ 条边由于都没显现出来,于是取值范围从 $k\sim M-1$,共 $M-k$ 种取值,于是有 $(M-k)^{{V(V-1)\over2}-L}$ 种情况。 对于只有一个端点在 $H$ 中的边,由于这种边如果显现,那么 $H$ 就和 $H$ 外的点连接了,与定义不符,于是这种边取值范围从 $k\sim M-1$,共 $M-k$ 种取值,于是有 $(M-k)^{V(N-V)}$ 种情况。 对于两个端点都不在 $H$ 中的边,由于与 $H$ 无关,所以就可以随便选,有 $M^{(N-V)(N-V-1)\over2}$ 种取值。 全部乘起来即可。 --- 我们发现后两项只与 $V$ 有关,于是可以设 $f(s)$ 表示有 $s$ 个节点的所有联通块 $H$ 的 $(M-k)^{{s(s-1)\over2}-L}\times k^L$ 的总和。 我们发现我们可以枚举 $s$。 由于我们要在 $N$ 个点中选 $s$ 个点组成联通块,于是要乘上 $\binom{N}{s}$。 根据乘法分配律,原式就可化为: $$ (N-1-M)\times M^{N(N-1)\over2}+\sum_{k=1}^{M}\sum_{s=1}^N\binom N s f(s)\times (M-k)^{s(N-s)}\times M^{(N-s)(N-s-1)\over2} $$ 现在我们的问题是如何快速求出 $f(s)$。 考虑容斥,于是可以用总方案数减去不构成联通块的方案数。 不构成联通块的方案数就是有小联通块独立出来,这和上面的式子很像。 于是我们直接 copy 过来。 $$ f(s)=M^{s(s-1)\over2}-\sum_{i=1}^{s-1}\binom s i f(i)\times (M-k)^{i(s-i)}\times M^{(s-i)(s-i-1)\over2} $$ 于是我们开心的打了代码,发现样例没过。 为什么? 我们发现,由于你连通块外的边乱选,就有可能也组成连通块,于是 $\binom s i$ 的时候会算重。 考虑如何去重。 我们可以钦定一个点一定在所选连通块内,那么无论其他如何组,都因为没有钦定的点而选不到。 于是就相当于 $\binom{s-1}{i-1}$。 原式即为: $$ f(s)=M^{s(s-1)\over2}-\sum_{i=1}^{s-1}\binom {s-1} {i-1} f(i)\times (M-k)^{i(s-i)}\times M^{(s-i)(s-i-1)\over2} $$ 时间复杂度 $\mathcal{O}(n^2m)$。 ## code ```cpp #include<bits/stdc++.h> #define int long long using namespace std; const int N=510; const int mod=998244353; int n,m,ans; int f[N]; int c[N][N],pp[N][N*N]; //c是杨辉三角预处理组合数,pp是预处理幂 signed main() { cin>>n>>m; for(int i=0;i<=500;i++){ c[i][0]=1; for(int j=1;j<=i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod; pp[i][0]=1; for(int j=1;j<=500*500;j++) pp[i][j]=pp[i][j-1]*i%mod; } ans=(n-1-m)*pp[m][n*(n-1)/2]%mod; for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ f[j]=pp[m][j*(j-1)/2]; for(int k=1;k<j;k++) f[j]=(f[j]-f[k]*c[j-1][k-1]%mod*pp[m-i][k*(j-k)]%mod*pp[m][(j-k)*(j-k-1)/2]%mod+mod)%mod; ans=(ans+c[n][j]*f[j]%mod*pp[m-i][j*(n-j)]%mod*pp[m][(n-j)*(n-j-1)/2]%mod)%mod; } } cout<<ans; return 0; } ```