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;
}
posted @ 2022-05-12 20:13  hzy0227  阅读(14)  评论(0编辑  收藏  举报