E. Star MST
题意:
定义一个无向完全图是 美丽的,当且仅当,每条边的边权 在
1
到
k
1到k
1到k 之间,且与
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;
}