CF EDU 125 E - Star MST
E - Star MST
给出一个 n 个顶点的完全图,边权可以从 [1, k] 中设置,求最小生成树的边权和 == 跟 1 相连的边权和的赋权方案
题意为 2 - n 号结点都与 1 号相连,这个生成树可以是最小生成树的方案数
dp
设 \(f[i][j]\) 为当前的生成树中边权最大为 \(i\), 且最大边权在 1 与别的点连成的边上,当前生成树中有 j 个顶点
初始:\(f[0][1]=1\)
转移:
若已知 \(f[i-1][j]\), 可从剩下 \(n-j\) 个点中选 a 个(\(\binom {n-j}a\)),令他们与 1 连的边权为 i,这些边要在最小生成树中,因此加上这 a 个点后,除了与 1 连的边以外新生成的边权要 >= i
这些边分为 a 与 2 ~ j 相连 \(a * (j - 1)\) 条 + 这 a 个点之间互相连 \(\binom a2\), 每条边有 \([i,k] = k-i+1\) 中选择
因此 \(f[i][j+a]+=f[i-1][j] * \binom {n-j}a*(k-i+1)^{a*(j-1)+\binom a2}\)
终态:\(f[k][n]\)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 260;
const int mod = 998244353;
ll f[N][N];//f[i][j]为当前最小生成树中最大边权为i,已经有了j个点
ll fac[N], finv[N];
int n, k;
ll qmi(ll a, ll b)
{
ll ans = 1;
while(b)
{
if (b & 1)
ans = ans * a % mod;
b >>= 1;
a = a * a % mod;
}
return ans % mod;
}
void presolve()
{
fac[0] = finv[0] = 1;
for (int i = 1; i < N; i++)
{
fac[i] = fac[i-1] * i % mod;
finv[i] = qmi(fac[i], mod - 2);
}
}
ll C(int n, int m)
{
if (m < 0 || n - m < 0)
return 0;
return fac[n] * finv[m] % mod * finv[n-m] % mod;
}
int main()
{
cin >> n >> k;
presolve();
f[0][1] = 1;
for (int i = 1; i <= k; i++)
{
for (int j = 1; j <= n; j++)
{
for (int a = 0; a + j <= n; a++)
{
//加 a 个与 1 的边长度为 i 的边,这些边参与组成最小生成树
f[i][j+a] += f[i-1][j] * C(n - j, a) % mod * qmi(k - i + 1, (j - 1) * a + C(a, 2)) % mod;
f[i][j+a] %= mod;
}
}
}
cout << f[k][n] << endl;
return 0;
}