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[i1][j], 可从剩下 nj 个点中选 a 个((nja)),令他们与 1 连的边权为 i,这些边要在最小生成树中,因此加上这 a 个点后,除了与 1 连的边以外新生成的边权要 >= i

这些边分为 a 与 2 ~ j 相连 a(j1) 条 + 这 a 个点之间互相连 (a2), 每条边有 [i,k]=ki+1 中选择

因此 f[i][j+a]+=f[i1][j](nja)(ki+1)a(j1)+(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 @   hzy0227  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示