E - Star MST
分析:
-
组合数学 + DP
-
只需要给出根节点出发的n-1条边的长度,剩下的边的长度,就是由这些边推出来的
具体原理详见大佬
-
d p [ i ] [ j ] dp[i][j] dp[i][j] 表示前i条边,最大边到j时的方案(总数)
#include <bits/stdc++.h>
#define int long long
#define Pa pair<int,int>
using namespace std;
const int N=255, mo=998244353;
int ksm(int a,int b,int p=mo,int res=1)
{
for( ; b ; a=a*a%p, b>>=1) if(b&1) res=res*a%p;
return res;
}
int fac[N],inv[N];
void init(int n=N-2)
{
inv[0]=fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mo;
inv[n]=ksm(fac[n],mo-2);
for(int i=n-1;i>=1;i--) inv[i]=inv[i+1]*(i+1)%mo;
}
int C(int n,int m)
{
return fac[n]*inv[m]%mo*inv[n-m]%mo;
}
int dp[N][N];
void solve()
{
init();
int n,k;
cin>>n>>k;
dp[0][0]=1;
for(int i=0;i<n;i++)
{
for(int j=1;j<=k;j++)
{
for(int t=0;t+i<n;t++)
{
(dp[i+t][j]+=dp[i][j-1]*C(n-1-i,t)%mo*ksm(k-j+1,t*i+t*(t-1)/2))%=mo;
//这一状态表示将要选取t个j,对于这t个j有n-1-i个位置能占
//t*i:每添加1条边会跟之前的i个便分别连线
//t*(t-1)/2:新加的边互相之间也会有连边
//连边的大小[j+1,k]:k-j+1种方案数
}
}
}
cout<<dp[n-1][k];
}
signed main()
{
int T=1;
//cin>>T;
while(T--) solve();
}
solution 2:
- 分析见上文的“大佬”
#include <bits/stdc++.h>
#define int long long
#define Pa pair<int,int>
using namespace std;
const int N=255, mo=998244353;
int ksm(int a,int b,int p=mo)
{
int res=1;
while(b)
{
if(b&1) res=res*a%p;
b>>=1; a=a*a%p;
}
return res;
}
int inv[N], pw[N][N*N];
void init(int n=N-3)
{
inv[0]=inv[1]=1;
for(int i=2;i<=n;i++) inv[i]=(mo-mo/i)*inv[mo%i]%mo;
for(int i=2;i<=n;i++) inv[i]=inv[i]*inv[i-1]%mo;
for(int i=0;i<=n;i++)
{
for(int j=0;j<=n*n;j++) pw[i][j]=ksm(i,j);
}
}
int dp[N][N];
void solve()
{
init();
int n,k;
cin>>n>>k;
dp[0][0]=1;
for(int i=1;i<=n;i++) for(int j=1;j<=k;j++)
for(int p=0;p<i;p++) for(int t=0;t<j;t++)
{
(dp[i][j]+=dp[p][t]*pw[k-j+1][(p+i-1)*(i-p)/2]%mo*inv[i-p])%=mo;
}
int ans=0;
for(int i=1;i<=k;i++)
{
(ans+=dp[n-1][i])%=mo;
}
for(int i=2;i<n;i++) ans=ans*i%mo;
cout<<ans<<"\n";
}
signed main()
{
int T=1;
//cin>>T;
while(T--) solve();
}