当前位置: 代码迷 >> 综合 >> Educational Codeforces Round 125 (Rated for Div. 2) E. Star MST
  详细解决方案

Educational Codeforces Round 125 (Rated for Div. 2) E. Star MST

热度:46   发布时间:2023-11-23 17:01:20.0

E. Star MST

题意:
定义一个无向完全图是 美丽的,当且仅当,每条边的边权 在 1 到 k 1到k 1k 之间,且与 1 1 1号点连接的边权和 等于 整张图最小生成树的权值和。
n < = 250 , k < = 250 n<=250,k<=250 n<=250,k<=250

思路:
既然题目涉及了 最小生成树,那肯定会想 克鲁斯卡尔算法,想象克鲁斯卡尔算法的过程 就是按照边权从小到大 加入边,直到所有点都联通。那么不妨加一个条件,当边权相同时,优先加入和 1 1 1号点相连的边。那么可以推断出,这个生成树算法 求得的最小生成树 如果要满足题目的条件,那么一定是一张菊花图,且根是 1 1 1 号点。

证明过程:
最小生成树中,和 1 1 1相连的边 是没有影响的,它的贡献是相互抵消的。
现在假设,有一个点 i i i 和点 j j j 相连,那么可以肯定 W i , j < W 1 , i W_{i,j}<W_{1,i} Wi,j?<W1,i?,即 现在的最小生成树的边权和 大于 1 1 1号结点连边的权值和,那么为了使两者相等,就要使 一个点 k k k 通过边权为 W W W的边连接在最小生成树中,且 W 1 , k < W W_{1,k}<W W1,k?<W,因为 W 1 , k W_{1,k} W1,k?的边权小,肯定会在 W W W 之前先加入最小生成树,所以假设不成立,得证。

通过这个性质,可以发现 W i , j > = m a x ( W 1 , i , W 1 , j ) W_{i,j}>=max(W_{1,i},W_{1,j}) Wi,j?>=max(W1,i?,W1,j?),也就是说,如果每条和 1 1 1点相连的边权确定的话,那么其他所有边的权值范围也确定了,方案数是可以直接算的。
接下来就是考虑怎么计算 和 1 1 1点相连的边的方案数了。
考虑 D P [ i ] [ j ] DP[i][j] DP[i][j],代表 前 i i i 中权值,总共连接了 j j j 条边的方案数,可以通过枚举当前这种权值连接了多少条来进行转移。不难发现,剩下权值小的几条不管怎么连, W i , j W_{i,j} Wi,j?都是由 W 1 , i W_{1,i} W1,i? 决定的,可以用前缀和优化转移。

具体转移见代码,小小两千分的题~
光速通过~
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
const ll mod=998244353;
ll qp(ll x,ll n){
    ll ans=1;while(n){
    if(n&1)ans=ans*x%mod;x=x*x%mod;n/=2; }return ans;
}
ll dp[255][254];
ll sum[255][255];
ll jie[255],inv[255];
ll C(ll n,ll m){
    if(m==0||n==m)return 1;return jie[n]*inv[n-m]%mod*inv[m]%mod;
} 
int n,k;
int main(){
    jie[0]=1;scanf("%d%d",&n,&k);for(int i=1;i<=n;i++){
    jie[i]=jie[i-1]*i%mod;}inv[n]=qp(jie[n],mod-2);for(int i=n;i>=1;i--){
    inv[i-1]=inv[i]*i%mod;}ll ans=0;for(int i=1;i<=k;i++){
    for(int j=1;j<n;j++){
    for(int l=1;l<=j;l++){
    int pre=j-l;ll res=C(n-pre-1,l)*qp(k-i+1,l*(l-1)/2+l*pre)%mod;if(pre!=0)res=res*sum[i-1][pre];dp[i][j]=(dp[i][j]+res)%mod; }sum[i][j]=(sum[i-1][j]+dp[i][j])%mod;ans=(ans+dp[i][n-1])%mod;}}printf("%lld\n",ans);return 0;
}
  相关解决方案